43 changes: 13 additions & 30 deletions clang/lib/CodeGen/Targets/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,37 +120,20 @@ class AArch64TargetCodeGenInfo : public TargetCodeGenInfo {
if (!FD)
return;

const auto *TA = FD->getAttr<TargetAttr>();
if (TA == nullptr)
return;

ParsedTargetAttr Attr =
CGM.getTarget().parseTargetAttr(TA->getFeaturesStr());
if (Attr.BranchProtection.empty())
return;

TargetInfo::BranchProtectionInfo BPI;
StringRef Error;
(void)CGM.getTarget().validateBranchProtection(Attr.BranchProtection,
Attr.CPU, BPI, Error);
assert(Error.empty());

auto *Fn = cast<llvm::Function>(GV);
Fn->addFnAttr("sign-return-address", BPI.getSignReturnAddrStr());

if (BPI.SignReturnAddr != LangOptions::SignReturnAddressScopeKind::None) {
Fn->addFnAttr("sign-return-address-key",
BPI.SignKey == LangOptions::SignReturnAddressKeyKind::AKey
? "a_key"
: "b_key");
TargetInfo::BranchProtectionInfo BPI(CGM.getLangOpts());

if (const auto *TA = FD->getAttr<TargetAttr>()) {
ParsedTargetAttr Attr =
CGM.getTarget().parseTargetAttr(TA->getFeaturesStr());
if (!Attr.BranchProtection.empty()) {
StringRef Error;
(void)CGM.getTarget().validateBranchProtection(Attr.BranchProtection,
Attr.CPU, BPI, Error);
assert(Error.empty());
}
}

Fn->addFnAttr("branch-target-enforcement",
BPI.BranchTargetEnforcement ? "true" : "false");
Fn->addFnAttr("branch-protection-pauth-lr",
BPI.BranchProtectionPAuthLR ? "true" : "false");
Fn->addFnAttr("guarded-control-stack",
BPI.GuardedControlStack ? "true" : "false");
auto *Fn = cast<llvm::Function>(GV);
BPI.setFnAttributes(*Fn);
}

bool isScalarizableAsmOperand(CodeGen::CodeGenFunction &CGF,
Expand Down
10 changes: 6 additions & 4 deletions clang/lib/CodeGen/Targets/ARM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ class ARMTargetCodeGenInfo : public TargetCodeGenInfo {
ParsedTargetAttr Attr =
CGM.getTarget().parseTargetAttr(TA->getFeaturesStr());
if (!Attr.BranchProtection.empty()) {
TargetInfo::BranchProtectionInfo BPI;
TargetInfo::BranchProtectionInfo BPI{};
StringRef DiagMsg;
StringRef Arch =
Attr.CPU.empty() ? CGM.getTarget().getTargetOpts().CPU : Attr.CPU;
Expand All @@ -152,9 +152,7 @@ class ARMTargetCodeGenInfo : public TargetCodeGenInfo {
diag::warn_target_unsupported_branch_protection_attribute)
<< Arch;
} else {
Fn->addFnAttr("sign-return-address", BPI.getSignReturnAddrStr());
Fn->addFnAttr("branch-target-enforcement",
BPI.BranchTargetEnforcement ? "true" : "false");
BPI.setFnAttributes(*Fn);
}
} else if (CGM.getLangOpts().BranchTargetEnforcement ||
CGM.getLangOpts().hasSignReturnAddress()) {
Expand All @@ -167,6 +165,10 @@ class ARMTargetCodeGenInfo : public TargetCodeGenInfo {
diag::warn_target_unsupported_branch_protection_attribute)
<< Attr.CPU;
}
} else if (CGM.getTarget().isBranchProtectionSupportedArch(
CGM.getTarget().getTargetOpts().CPU)) {
TargetInfo::BranchProtectionInfo BPI(CGM.getLangOpts());
BPI.setFnAttributes(*Fn);
}

const ARMInterruptAttr *Attr = FD->getAttr<ARMInterruptAttr>();
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Driver/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4367,6 +4367,7 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
return;
}
if (Opt == options::OPT_print_enabled_extensions &&
!C.getDefaultToolChain().getTriple().isRISCV() &&
!C.getDefaultToolChain().getTriple().isAArch64()) {
C.getDriver().Diag(diag::err_opt_not_valid_on_target)
<< "--print-enabled-extensions";
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Driver/ToolChains/Arch/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,9 @@ void aarch64::getAArch64TargetFeatures(const Driver &D,
if (Args.hasArg(options::OPT_ffixed_x28))
Features.push_back("+reserve-x28");

if (Args.hasArg(options::OPT_mlr_for_calls_only))
Features.push_back("+reserve-lr-for-ra");

if (Args.hasArg(options::OPT_fcall_saved_x8))
Features.push_back("+call-saved-x8");

Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5751,6 +5751,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_fexperimental_omit_vtable_rtti,
options::OPT_fno_experimental_omit_vtable_rtti);

Args.AddLastArg(CmdArgs, options::OPT_fdisable_block_signature_string,
options::OPT_fno_disable_block_signature_string);

// Handle segmented stacks.
Args.addOptInFlag(CmdArgs, options::OPT_fsplit_stack,
options::OPT_fno_split_stack);
Expand Down Expand Up @@ -6516,6 +6519,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions);
Args.AddLastArg(CmdArgs, options::OPT_fdigraphs, options::OPT_fno_digraphs);
Args.AddLastArg(CmdArgs, options::OPT_fzero_call_used_regs_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fraw_string_literals,
options::OPT_fno_raw_string_literals);

if (Args.hasFlag(options::OPT_femulated_tls, options::OPT_fno_emulated_tls,
Triple.hasDefaultEmulatedTLS()))
Expand Down
35 changes: 4 additions & 31 deletions clang/lib/Driver/ToolChains/Gnu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -672,41 +672,12 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
}
}

// Facebook T92898286
if (Args.hasArg(options::OPT_post_link_optimize))
CmdArgs.push_back("-q");
// End Facebook T92898286

Args.AddAllArgs(CmdArgs, options::OPT_T);

const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
C.addCommand(std::make_unique<Command>(JA, *this,
ResponseFileSupport::AtFileCurCP(),
Exec, CmdArgs, Inputs, Output));
// Facebook T92898286
if (!Args.hasArg(options::OPT_post_link_optimize) || !Output.isFilename())
return;

const char *MvExec = Args.MakeArgString(ToolChain.GetProgramPath("mv"));
ArgStringList MoveCmdArgs;
MoveCmdArgs.push_back(Output.getFilename());
const char *PreBoltBin =
Args.MakeArgString(Twine(Output.getFilename()) + ".pre-bolt");
MoveCmdArgs.push_back(PreBoltBin);
C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
MvExec, MoveCmdArgs, std::nullopt));

ArgStringList BoltCmdArgs;
const char *BoltExec =
Args.MakeArgString(ToolChain.GetProgramPath("llvm-bolt"));
BoltCmdArgs.push_back(PreBoltBin);
BoltCmdArgs.push_back("-reorder-blocks=reverse");
BoltCmdArgs.push_back("-update-debug-sections");
BoltCmdArgs.push_back("-o");
BoltCmdArgs.push_back(Output.getFilename());
C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
BoltExec, BoltCmdArgs, std::nullopt));
// End Facebook T92898286
}

void tools::gnutools::Assembler::ConstructJob(Compilation &C,
Expand Down Expand Up @@ -2593,9 +2564,11 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
"riscv64-unknown-elf"};

static const char *const SPARCv8LibDirs[] = {"/lib32", "/lib"};
static const char *const SPARCv8Triples[] = {"sparcv8-linux-gnu"};
static const char *const SPARCv8Triples[] = {"sparc-linux-gnu",
"sparcv8-linux-gnu"};
static const char *const SPARCv9LibDirs[] = {"/lib64", "/lib"};
static const char *const SPARCv9Triples[] = {"sparcv9-linux-gnu"};
static const char *const SPARCv9Triples[] = {"sparc64-linux-gnu",
"sparcv9-linux-gnu"};

static const char *const SystemZLibDirs[] = {"/lib64", "/lib"};
static const char *const SystemZTriples[] = {
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Format/FormatToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ namespace format {
TYPE(ForEachMacro) \
TYPE(FunctionAnnotationRParen) \
TYPE(FunctionDeclarationName) \
TYPE(FunctionDeclarationLParen) \
TYPE(FunctionLBrace) \
TYPE(FunctionLikeOrFreestandingMacro) \
TYPE(FunctionTypeLParen) \
Expand Down
24 changes: 18 additions & 6 deletions clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3539,7 +3539,8 @@ static unsigned maxNestingDepth(const AnnotatedLine &Line) {

// Returns the name of a function with no return type, e.g. a constructor or
// destructor.
static FormatToken *getFunctionName(const AnnotatedLine &Line) {
static FormatToken *getFunctionName(const AnnotatedLine &Line,
FormatToken *&OpeningParen) {
for (FormatToken *Tok = Line.getFirstNonComment(), *Name = nullptr; Tok;
Tok = Tok->getNextNonComment()) {
// Skip C++11 attributes both before and after the function name.
Expand All @@ -3552,10 +3553,12 @@ static FormatToken *getFunctionName(const AnnotatedLine &Line) {

// Make sure the name is followed by a pair of parentheses.
if (Name) {
return Tok->is(tok::l_paren) && Tok->isNot(TT_FunctionTypeLParen) &&
Tok->MatchingParen
? Name
: nullptr;
if (Tok->is(tok::l_paren) && Tok->isNot(TT_FunctionTypeLParen) &&
Tok->MatchingParen) {
OpeningParen = Tok;
return Name;
}
return nullptr;
}

// Skip keywords that may precede the constructor/destructor name.
Expand Down Expand Up @@ -3632,10 +3635,13 @@ void TokenAnnotator::annotate(AnnotatedLine &Line) {
ExprParser.parse();

if (IsCpp) {
auto *Tok = getFunctionName(Line);
FormatToken *OpeningParen = nullptr;
auto *Tok = getFunctionName(Line, OpeningParen);
if (Tok && ((!Scopes.empty() && Scopes.back() == ST_Class) ||
Line.endsWith(TT_FunctionLBrace) || isCtorOrDtorName(Tok))) {
Tok->setFinalizedType(TT_CtorDtorDeclName);
assert(OpeningParen);
OpeningParen->setFinalizedType(TT_FunctionDeclarationLParen);
}
}

Expand Down Expand Up @@ -3864,6 +3870,12 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) const {
Tok->setFinalizedType(TT_FunctionDeclarationName);
LineIsFunctionDeclaration = true;
SeenName = true;
if (ClosingParen) {
auto *OpeningParen = ClosingParen->MatchingParen;
assert(OpeningParen);
if (OpeningParen->is(TT_Unknown))
OpeningParen->setType(TT_FunctionDeclarationLParen);
}
break;
}
}
Expand Down
13 changes: 13 additions & 0 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,19 @@ static bool FixupInvocation(CompilerInvocation &Invocation,
LangOpts.NewAlignOverride = 0;
}

// The -f[no-]raw-string-literals option is only valid in C and in C++
// standards before C++11.
if (LangOpts.CPlusPlus11) {
if (Args.hasArg(OPT_fraw_string_literals, OPT_fno_raw_string_literals)) {
Args.claimAllArgs(OPT_fraw_string_literals, OPT_fno_raw_string_literals);
Diags.Report(diag::warn_drv_fraw_string_literals_in_cxx11)
<< bool(LangOpts.RawStringLiterals);
}

// Do not allow disabling raw string literals in C++11 or later.
LangOpts.RawStringLiterals = true;
}

// Prevent the user from specifying both -fsycl-is-device and -fsycl-is-host.
if (LangOpts.SYCLIsDevice && LangOpts.SYCLIsHost)
Diags.Report(diag::err_drv_argument_not_allowed_with) << "-fsycl-is-device"
Expand Down
7 changes: 6 additions & 1 deletion clang/lib/Frontend/InitPreprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,11 @@ static T PickFP(const llvm::fltSemantics *Sem, T IEEEHalfVal, T IEEESingleVal,

static void DefineFloatMacros(MacroBuilder &Builder, StringRef Prefix,
const llvm::fltSemantics *Sem, StringRef Ext) {
const char *DenormMin, *Epsilon, *Max, *Min;
const char *DenormMin, *NormMax, *Epsilon, *Max, *Min;
NormMax = PickFP(Sem, "6.5504e+4", "3.40282347e+38",
"1.7976931348623157e+308", "1.18973149535723176502e+4932",
"8.98846567431157953864652595394501e+307",
"1.18973149535723176508575932662800702e+4932");
DenormMin = PickFP(Sem, "5.9604644775390625e-8", "1.40129846e-45",
"4.9406564584124654e-324", "3.64519953188247460253e-4951",
"4.94065645841246544176568792868221e-324",
Expand Down Expand Up @@ -144,6 +148,7 @@ static void DefineFloatMacros(MacroBuilder &Builder, StringRef Prefix,
DefPrefix += "_";

Builder.defineMacro(DefPrefix + "DENORM_MIN__", Twine(DenormMin)+Ext);
Builder.defineMacro(DefPrefix + "NORM_MAX__", Twine(NormMax)+Ext);
Builder.defineMacro(DefPrefix + "HAS_DENORM__");
Builder.defineMacro(DefPrefix + "DIG__", Twine(Digits));
Builder.defineMacro(DefPrefix + "DECIMAL_DIG__", Twine(DecimalDigits));
Expand Down
10 changes: 10 additions & 0 deletions clang/lib/Headers/float.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,12 @@
# undef DBL_HAS_SUBNORM
# undef LDBL_HAS_SUBNORM
# endif
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L) || \
!defined(__STRICT_ANSI__)
# undef FLT_NORM_MAX
# undef DBL_NORM_MAX
# undef LDBL_NORM_MAX
#endif
#endif

#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L) || \
Expand Down Expand Up @@ -166,6 +172,10 @@
/* C23 5.2.5.3.3p29-30 */
# define INFINITY (__builtin_inff())
# define NAN (__builtin_nanf(""))
/* C23 5.2.5.3.3p32 */
# define FLT_NORM_MAX __FLT_NORM_MAX__
# define DBL_NORM_MAX __DBL_NORM_MAX__
# define LDBL_NORM_MAX __LDBL_NORM_MAX__
#endif

#ifdef __STDC_WANT_IEC_60559_TYPES_EXT__
Expand Down
8 changes: 6 additions & 2 deletions clang/lib/InstallAPI/DylibVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,14 +187,18 @@ bool DylibVerifier::shouldIgnoreObsolete(const Record *R, SymbolContext &SymCtx,

bool DylibVerifier::shouldIgnoreReexport(const Record *R,
SymbolContext &SymCtx) const {
StringRef SymName = SymCtx.SymbolName;
// Linker directive symbols can never be ignored.
if (SymName.starts_with("$ld$"))
return false;

if (Reexports.empty())
return false;

for (const InterfaceFile &Lib : Reexports) {
if (!Lib.hasTarget(Ctx.Target))
continue;
if (auto Sym =
Lib.getSymbol(SymCtx.Kind, SymCtx.SymbolName, SymCtx.ObjCIFKind))
if (auto Sym = Lib.getSymbol(SymCtx.Kind, SymName, SymCtx.ObjCIFKind))
if ((*Sym)->hasTarget(Ctx.Target))
return true;
}
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Lex/DependencyDirectivesScanner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ struct Scanner {
// Set the lexer to use 'tok::at' for '@', instead of 'tok::unknown'.
LangOpts.ObjC = true;
LangOpts.LineComment = true;
// FIXME: we do not enable C11 or C++11, so we are missing u/u8/U"" and
// R"()" literals.
LangOpts.RawStringLiterals = true;
// FIXME: we do not enable C11 or C++11, so we are missing u/u8/U"".
return LangOpts;
}

Expand Down
10 changes: 5 additions & 5 deletions clang/lib/Lex/Lexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3876,7 +3876,7 @@ bool Lexer::LexTokenInternal(Token &Result, bool TokAtPhysicalStartOfLine) {
tok::utf16_char_constant);

// UTF-16 raw string literal
if (Char == 'R' && LangOpts.CPlusPlus11 &&
if (Char == 'R' && LangOpts.RawStringLiterals &&
getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == '"')
return LexRawStringLiteral(Result,
ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
Expand All @@ -3898,7 +3898,7 @@ bool Lexer::LexTokenInternal(Token &Result, bool TokAtPhysicalStartOfLine) {
SizeTmp2, Result),
tok::utf8_char_constant);

if (Char2 == 'R' && LangOpts.CPlusPlus11) {
if (Char2 == 'R' && LangOpts.RawStringLiterals) {
unsigned SizeTmp3;
char Char3 = getCharAndSize(CurPtr + SizeTmp + SizeTmp2, SizeTmp3);
// UTF-8 raw string literal
Expand Down Expand Up @@ -3934,7 +3934,7 @@ bool Lexer::LexTokenInternal(Token &Result, bool TokAtPhysicalStartOfLine) {
tok::utf32_char_constant);

// UTF-32 raw string literal
if (Char == 'R' && LangOpts.CPlusPlus11 &&
if (Char == 'R' && LangOpts.RawStringLiterals &&
getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == '"')
return LexRawStringLiteral(Result,
ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
Expand All @@ -3949,7 +3949,7 @@ bool Lexer::LexTokenInternal(Token &Result, bool TokAtPhysicalStartOfLine) {
// Notify MIOpt that we read a non-whitespace/non-comment token.
MIOpt.ReadToken();

if (LangOpts.CPlusPlus11) {
if (LangOpts.RawStringLiterals) {
Char = getCharAndSize(CurPtr, SizeTmp);

if (Char == '"')
Expand All @@ -3972,7 +3972,7 @@ bool Lexer::LexTokenInternal(Token &Result, bool TokAtPhysicalStartOfLine) {
tok::wide_string_literal);

// Wide raw string literal.
if (LangOpts.CPlusPlus11 && Char == 'R' &&
if (LangOpts.RawStringLiterals && Char == 'R' &&
getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == '"')
return LexRawStringLiteral(Result,
ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
Expand Down
25 changes: 16 additions & 9 deletions clang/lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -593,7 +593,9 @@ unsigned Parser::ParseAttributeArgsCommon(
EnterExpressionEvaluationContext Unevaluated(
Actions,
Uneval ? Sema::ExpressionEvaluationContext::Unevaluated
: Sema::ExpressionEvaluationContext::ConstantEvaluated);
: Sema::ExpressionEvaluationContext::ConstantEvaluated,
nullptr,
Sema::ExpressionEvaluationContextRecord::EK_AttrArgument);

ExprResult ArgExpr(
Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()));
Expand All @@ -610,9 +612,12 @@ unsigned Parser::ParseAttributeArgsCommon(
// General case. Parse all available expressions.
bool Uneval = attributeParsedArgsUnevaluated(*AttrName);
EnterExpressionEvaluationContext Unevaluated(
Actions, Uneval
? Sema::ExpressionEvaluationContext::Unevaluated
: Sema::ExpressionEvaluationContext::ConstantEvaluated);
Actions,
Uneval ? Sema::ExpressionEvaluationContext::Unevaluated
: Sema::ExpressionEvaluationContext::ConstantEvaluated,
nullptr,
Sema::ExpressionEvaluationContextRecord::ExpressionKind::
EK_AttrArgument);

ExprVector ParsedExprs;
ParsedAttributeArgumentsProperties ArgProperties =
Expand Down Expand Up @@ -695,7 +700,10 @@ void Parser::ParseGNUAttributeArgs(
ParseAttributeWithTypeArg(*AttrName, AttrNameLoc, Attrs, ScopeName,
ScopeLoc, Form);
return;
} else if (AttrKind == ParsedAttr::AT_CountedBy) {
} else if (AttrKind == ParsedAttr::AT_CountedBy ||
AttrKind == ParsedAttr::AT_CountedByOrNull ||
AttrKind == ParsedAttr::AT_SizedBy ||
AttrKind == ParsedAttr::AT_SizedByOrNull) {
ParseBoundsAttribute(*AttrName, AttrNameLoc, Attrs, ScopeName, ScopeLoc,
Form);
return;
Expand Down Expand Up @@ -3383,7 +3391,7 @@ void Parser::ParseBoundsAttribute(IdentifierInfo &AttrName,
Sema::ExpressionEvaluationContextRecord::ExpressionKind;
EnterExpressionEvaluationContext EC(
Actions, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, nullptr,
ExpressionKind::EK_BoundsAttrArgument);
ExpressionKind::EK_AttrArgument);

ExprResult ArgExpr(
Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()));
Expand Down Expand Up @@ -4861,9 +4869,8 @@ static void DiagnoseCountAttributedTypeInUnnamedAnon(ParsingDeclSpec &DS,

for (const auto &DD : CAT->dependent_decls()) {
if (!RD->containsDecl(DD.getDecl())) {
P.Diag(VD->getBeginLoc(),
diag::err_flexible_array_count_not_in_same_struct)
<< DD.getDecl();
P.Diag(VD->getBeginLoc(), diag::err_count_attr_param_not_in_same_struct)
<< DD.getDecl() << CAT->getKind() << CAT->isArrayType();
P.Diag(DD.getDecl()->getBeginLoc(),
diag::note_flexible_array_counted_by_attr_field)
<< DD.getDecl();
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Sema/SemaAPINotes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,7 @@ static void ProcessAPINotes(Sema &S, TypedefNameDecl *D,

/// Process API notes for an Objective-C class or protocol.
static void ProcessAPINotes(Sema &S, ObjCContainerDecl *D,
const api_notes::ObjCContextInfo &Info,
const api_notes::ContextInfo &Info,
VersionedInfoMetadata Metadata) {
// Handle common type information.
ProcessAPINotes(S, D, static_cast<const api_notes::CommonTypeInfo &>(Info),
Expand All @@ -683,7 +683,7 @@ static void ProcessAPINotes(Sema &S, ObjCContainerDecl *D,

/// Process API notes for an Objective-C class.
static void ProcessAPINotes(Sema &S, ObjCInterfaceDecl *D,
const api_notes::ObjCContextInfo &Info,
const api_notes::ContextInfo &Info,
VersionedInfoMetadata Metadata) {
if (auto AsNonGeneric = Info.getSwiftImportAsNonGeneric()) {
handleAPINotedAttribute<SwiftImportAsNonGenericAttr>(
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Sema/SemaARM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1329,6 +1329,10 @@ void SemaARM::handleInterruptAttr(Decl *D, const ParsedAttr &AL) {
return;
}

const TargetInfo &TI = getASTContext().getTargetInfo();
if (TI.hasFeature("vfp"))
Diag(D->getLocation(), diag::warn_arm_interrupt_vfp_clobber);

D->addAttr(::new (getASTContext())
ARMInterruptAttr(getASTContext(), AL, Kind));
}
Expand Down
14 changes: 4 additions & 10 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10094,7 +10094,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// check at the end of the TU (or when the PMF starts) to see that we
// have a definition at that point.
if (isInline && !D.isFunctionDefinition() && getLangOpts().CPlusPlus20 &&
NewFD->isInNamedModule()) {
NewFD->hasOwningModule() && NewFD->getOwningModule()->isNamedModule()) {
PendingInlineFuncDecls.insert(NewFD);
}
}
Expand Down Expand Up @@ -15222,6 +15222,9 @@ ShouldWarnAboutMissingPrototype(const FunctionDecl *FD,
if (II->isStr("main") || II->isStr("efi_main"))
return false;

if (FD->isMSVCRTEntryPoint())
return false;

// Don't warn about inline functions.
if (FD->isInlined())
return false;
Expand Down Expand Up @@ -18028,15 +18031,6 @@ void Sema::ActOnTagFinishDefinition(Scope *S, Decl *TagD,
if (NumInitMethods > 1 || !Def->hasInitMethod())
Diag(RD->getLocation(), diag::err_sycl_special_type_num_init_method);
}

// If we're defining a dynamic class in a module interface unit, we always
// need to produce the vtable for it even if the vtable is not used in the
// current TU.
//
// The case that the current class is not dynamic is handled in
// MarkVTableUsed.
if (getCurrentModule() && getCurrentModule()->isInterfaceOrPartition())
MarkVTableUsed(RD->getLocation(), RD, /*DefinitionRequired=*/true);
}

// Exit this scope of this tag's definition.
Expand Down
93 changes: 68 additions & 25 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2991,7 +2991,7 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
<< Unsupported << None << CurFeature << Target;
}

TargetInfo::BranchProtectionInfo BPI;
TargetInfo::BranchProtectionInfo BPI{};
StringRef DiagMsg;
if (ParsedAttrs.BranchProtection.empty())
return false;
Expand Down Expand Up @@ -5868,6 +5868,15 @@ static const RecordDecl *GetEnclosingNamedOrTopAnonRecord(const FieldDecl *FD) {
return RD;
}

static CountAttributedType::DynamicCountPointerKind
getCountAttrKind(bool CountInBytes, bool OrNull) {
if (CountInBytes)
return OrNull ? CountAttributedType::SizedByOrNull
: CountAttributedType::SizedBy;
return OrNull ? CountAttributedType::CountedByOrNull
: CountAttributedType::CountedBy;
}

enum class CountedByInvalidPointeeTypeKind {
INCOMPLETE,
SIZELESS,
Expand All @@ -5876,22 +5885,31 @@ enum class CountedByInvalidPointeeTypeKind {
VALID,
};

static bool CheckCountedByAttrOnField(
Sema &S, FieldDecl *FD, Expr *E,
llvm::SmallVectorImpl<TypeCoupledDeclRefInfo> &Decls) {
static bool
CheckCountedByAttrOnField(Sema &S, FieldDecl *FD, Expr *E,
llvm::SmallVectorImpl<TypeCoupledDeclRefInfo> &Decls,
bool CountInBytes, bool OrNull) {
// Check the context the attribute is used in

unsigned Kind = getCountAttrKind(CountInBytes, OrNull);

if (FD->getParent()->isUnion()) {
S.Diag(FD->getBeginLoc(), diag::err_counted_by_attr_in_union)
<< FD->getSourceRange();
S.Diag(FD->getBeginLoc(), diag::err_count_attr_in_union)
<< Kind << FD->getSourceRange();
return true;
}

const auto FieldTy = FD->getType();
if (FieldTy->isArrayType() && (CountInBytes || OrNull)) {
S.Diag(FD->getBeginLoc(),
diag::err_count_attr_not_on_ptr_or_flexible_array_member)
<< Kind << FD->getLocation() << /* suggest counted_by */ 1;
return true;
}
if (!FieldTy->isArrayType() && !FieldTy->isPointerType()) {
S.Diag(FD->getBeginLoc(),
diag::err_counted_by_attr_not_on_ptr_or_flexible_array_member)
<< FD->getLocation();
diag::err_count_attr_not_on_ptr_or_flexible_array_member)
<< Kind << FD->getLocation() << /* do not suggest counted_by */ 0;
return true;
}

Expand All @@ -5902,7 +5920,7 @@ static bool CheckCountedByAttrOnField(
StrictFlexArraysLevel, true)) {
S.Diag(FD->getBeginLoc(),
diag::err_counted_by_attr_on_array_not_flexible_array_member)
<< FD->getLocation();
<< Kind << FD->getLocation();
return true;
}

Expand All @@ -5923,7 +5941,7 @@ static bool CheckCountedByAttrOnField(
// only `PointeeTy->isStructureTypeWithFlexibleArrayMember()` is reachable
// when `FieldTy->isArrayType()`.
bool ShouldWarn = false;
if (PointeeTy->isIncompleteType()) {
if (PointeeTy->isIncompleteType() && !CountInBytes) {
InvalidTypeKind = CountedByInvalidPointeeTypeKind::INCOMPLETE;
} else if (PointeeTy->isSizelessType()) {
InvalidTypeKind = CountedByInvalidPointeeTypeKind::SIZELESS;
Expand All @@ -5948,23 +5966,23 @@ static bool CheckCountedByAttrOnField(
: diag::err_counted_by_attr_pointee_unknown_size;
S.Diag(FD->getBeginLoc(), DiagID)
<< SelectPtrOrArr << PointeeTy << (int)InvalidTypeKind
<< (ShouldWarn ? 1 : 0) << FD->getSourceRange();
<< (ShouldWarn ? 1 : 0) << Kind << FD->getSourceRange();
return true;
}

// Check the expression

if (!E->getType()->isIntegerType() || E->getType()->isBooleanType()) {
S.Diag(E->getBeginLoc(), diag::err_counted_by_attr_argument_not_integer)
<< E->getSourceRange();
S.Diag(E->getBeginLoc(), diag::err_count_attr_argument_not_integer)
<< Kind << E->getSourceRange();
return true;
}

auto *DRE = dyn_cast<DeclRefExpr>(E);
if (!DRE) {
S.Diag(E->getBeginLoc(),
diag::err_counted_by_attr_only_support_simple_decl_reference)
<< E->getSourceRange();
diag::err_count_attr_only_support_simple_decl_reference)
<< Kind << E->getSourceRange();
return true;
}

Expand All @@ -5974,8 +5992,8 @@ static bool CheckCountedByAttrOnField(
CountFD = IFD->getAnonField();
}
if (!CountFD) {
S.Diag(E->getBeginLoc(), diag::err_counted_by_must_be_in_structure)
<< CountDecl << E->getSourceRange();
S.Diag(E->getBeginLoc(), diag::err_count_attr_must_be_in_structure)
<< CountDecl << Kind << E->getSourceRange();

S.Diag(CountDecl->getBeginLoc(),
diag::note_flexible_array_counted_by_attr_field)
Expand All @@ -5985,8 +6003,8 @@ static bool CheckCountedByAttrOnField(

if (FD->getParent() != CountFD->getParent()) {
if (CountFD->getParent()->isUnion()) {
S.Diag(CountFD->getBeginLoc(), diag::err_counted_by_attr_refer_to_union)
<< CountFD->getSourceRange();
S.Diag(CountFD->getBeginLoc(), diag::err_count_attr_refer_to_union)
<< Kind << CountFD->getSourceRange();
return true;
}
// Whether CountRD is an anonymous struct is not determined at this
Expand All @@ -5996,9 +6014,8 @@ static bool CheckCountedByAttrOnField(
auto *CountRD = GetEnclosingNamedOrTopAnonRecord(CountFD);

if (RD != CountRD) {
S.Diag(E->getBeginLoc(),
diag::err_flexible_array_count_not_in_same_struct)
<< CountFD << E->getSourceRange();
S.Diag(E->getBeginLoc(), diag::err_count_attr_param_not_in_same_struct)
<< CountFD << Kind << FieldTy->isArrayType() << E->getSourceRange();
S.Diag(CountFD->getBeginLoc(),
diag::note_flexible_array_counted_by_attr_field)
<< CountFD << CountFD->getSourceRange();
Expand All @@ -6018,12 +6035,35 @@ static void handleCountedByAttrField(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!CountExpr)
return;

bool CountInBytes;
bool OrNull;
switch (AL.getKind()) {
case ParsedAttr::AT_CountedBy:
CountInBytes = false;
OrNull = false;
break;
case ParsedAttr::AT_CountedByOrNull:
CountInBytes = false;
OrNull = true;
break;
case ParsedAttr::AT_SizedBy:
CountInBytes = true;
OrNull = false;
break;
case ParsedAttr::AT_SizedByOrNull:
CountInBytes = true;
OrNull = true;
break;
default:
llvm_unreachable("unexpected counted_by family attribute");
}

llvm::SmallVector<TypeCoupledDeclRefInfo, 1> Decls;
if (CheckCountedByAttrOnField(S, FD, CountExpr, Decls))
if (CheckCountedByAttrOnField(S, FD, CountExpr, Decls, CountInBytes, OrNull))
return;

QualType CAT =
S.BuildCountAttributedArrayOrPointerType(FD->getType(), CountExpr);
QualType CAT = S.BuildCountAttributedArrayOrPointerType(
FD->getType(), CountExpr, CountInBytes, OrNull);
FD->setType(CAT);
}

Expand Down Expand Up @@ -6971,6 +7011,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
break;

case ParsedAttr::AT_CountedBy:
case ParsedAttr::AT_CountedByOrNull:
case ParsedAttr::AT_SizedBy:
case ParsedAttr::AT_SizedByOrNull:
handleCountedByAttrField(S, D, AL);
break;

Expand Down
14 changes: 5 additions & 9 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18456,15 +18456,11 @@ bool Sema::DefineUsedVTables() {

bool DefineVTable = true;

// If this class has a key function, but that key function is
// defined in another translation unit, we don't need to emit the
// vtable even though we're using it.
const CXXMethodDecl *KeyFunction = Context.getCurrentKeyFunction(Class);
// V-tables for non-template classes with an owning module are always
// uniquely emitted in that module.
if (Class->isInCurrentModuleUnit())
DefineVTable = true;
else if (KeyFunction && !KeyFunction->hasBody()) {
// If this class has a key function, but that key function is
// defined in another translation unit, we don't need to emit the
// vtable even though we're using it.
if (KeyFunction && !KeyFunction->hasBody()) {
// The key function is in another translation unit.
DefineVTable = false;
TemplateSpecializationKind TSK =
Expand Down Expand Up @@ -18509,7 +18505,7 @@ bool Sema::DefineUsedVTables() {
DefinedAnything = true;
MarkVirtualMembersReferenced(Loc, Class);
CXXRecordDecl *Canonical = Class->getCanonicalDecl();
if (VTablesUsed[Canonical] && !Class->shouldEmitInExternalSource())
if (VTablesUsed[Canonical])
Consumer.HandleVTable(Class);

// Warn if we're emitting a weak vtable. The vtable will be weak if there is
Expand Down
37 changes: 15 additions & 22 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2666,11 +2666,10 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
return ExprError();
}

// BoundsSafety: This specially handles arguments of bounds attributes
// appertains to a type of C struct field such that the name lookup
// within a struct finds the member name, which is not the case for other
// contexts in C.
if (isBoundsAttrContext() && !getLangOpts().CPlusPlus && S->isClassScope()) {
// This specially handles arguments of attributes appertains to a type of C
// struct field such that the name lookup within a struct finds the member
// name, which is not the case for other contexts in C.
if (isAttrContext() && !getLangOpts().CPlusPlus && S->isClassScope()) {
// See if this is reference to a field of struct.
LookupResult R(*this, NameInfo, LookupMemberName);
// LookupName handles a name lookup from within anonymous struct.
Expand Down Expand Up @@ -3279,7 +3278,7 @@ ExprResult Sema::BuildDeclarationNameExpr(
case Decl::Field:
case Decl::IndirectField:
case Decl::ObjCIvar:
assert((getLangOpts().CPlusPlus || isBoundsAttrContext()) &&
assert((getLangOpts().CPlusPlus || isAttrContext()) &&
"building reference to field in C?");

// These can't have reference type in well-formed programs, but
Expand Down Expand Up @@ -6626,27 +6625,21 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
unsigned BuiltinID = (FDecl ? FDecl->getBuiltinID() : 0);

// Functions with 'interrupt' attribute cannot be called directly.
if (FDecl && FDecl->hasAttr<AnyX86InterruptAttr>()) {
Diag(Fn->getExprLoc(), diag::err_anyx86_interrupt_called);
return ExprError();
if (FDecl) {
if (FDecl->hasAttr<AnyX86InterruptAttr>()) {
Diag(Fn->getExprLoc(), diag::err_anyx86_interrupt_called);
return ExprError();
}
if (FDecl->hasAttr<ARMInterruptAttr>()) {
Diag(Fn->getExprLoc(), diag::err_arm_interrupt_called);
return ExprError();
}
}

// Interrupt handlers don't save off the VFP regs automatically on ARM,
// so there's some risk when calling out to non-interrupt handler functions
// that the callee might not preserve them. This is easy to diagnose here,
// but can be very challenging to debug.
// Likewise, X86 interrupt handlers may only call routines with attribute
// X86 interrupt handlers may only call routines with attribute
// no_caller_saved_registers since there is no efficient way to
// save and restore the non-GPR state.
if (auto *Caller = getCurFunctionDecl()) {
if (Caller->hasAttr<ARMInterruptAttr>()) {
bool VFP = Context.getTargetInfo().hasFeature("vfp");
if (VFP && (!FDecl || !FDecl->hasAttr<ARMInterruptAttr>())) {
Diag(Fn->getExprLoc(), diag::warn_arm_interrupt_calling_convention);
if (FDecl)
Diag(FDecl->getLocation(), diag::note_callee_decl) << FDecl;
}
}
if (Caller->hasAttr<AnyX86InterruptAttr>() ||
Caller->hasAttr<AnyX86NoCallerSavedRegistersAttr>()) {
const TargetInfo &TI = Context.getTargetInfo();
Expand Down
17 changes: 7 additions & 10 deletions clang/lib/Sema/SemaExprMember.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -789,9 +789,6 @@ ExprResult Sema::BuildMemberReferenceExpr(
ActOnMemberAccessExtraArgs *ExtraArgs) {
LookupResult R(*this, NameInfo, LookupMemberName);

if (SS.isInvalid())
return ExprError();

// Implicit member accesses.
if (!Base) {
TypoExpr *TE = nullptr;
Expand Down Expand Up @@ -826,6 +823,11 @@ ExprResult Sema::BuildMemberReferenceExpr(
BaseType = Base->getType();
}

// BuildMemberReferenceExpr expects the nested-name-specifier, if any, to be
// valid.
if (SS.isInvalid())
return ExprError();

return BuildMemberReferenceExpr(Base, BaseType,
OpLoc, IsArrow, SS, TemplateKWLoc,
FirstQualifierInScope, R, TemplateArgs, S,
Expand Down Expand Up @@ -1745,14 +1747,9 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,

ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
CXXScopeSpec &SS,
tok::TokenKind OpKind, CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
UnqualifiedId &Id,
Decl *ObjCImpDecl) {
if (SS.isSet() && SS.isInvalid())
return ExprError();

UnqualifiedId &Id, Decl *ObjCImpDecl) {
// Warn about the explicit constructor calls Microsoft extension.
if (getLangOpts().MicrosoftExt &&
Id.getKind() == UnqualifiedIdKind::IK_ConstructorName)
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Sema/SemaInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5576,6 +5576,10 @@ static void TryOrBuildParenListInitialization(
ExprResult ER;
ER = IS.Perform(S, SubEntity, SubKind,
Arg ? MultiExprArg(Arg) : std::nullopt);

if (ER.isInvalid())
return false;

if (InitExpr)
*InitExpr = ER.get();
else
Expand Down
42 changes: 28 additions & 14 deletions clang/lib/Sema/SemaLambda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2383,23 +2383,37 @@ Sema::LambdaScopeForCallOperatorInstantiationRAII::

SemaRef.RebuildLambdaScopeInfo(cast<CXXMethodDecl>(FD));

FunctionDecl *Pattern = getPatternFunctionDecl(FD);
if (Pattern) {
SemaRef.addInstantiatedCapturesToScope(FD, Pattern, Scope, MLTAL);
FunctionDecl *FDPattern = getPatternFunctionDecl(FD);
if (!FDPattern)
return;

FunctionDecl *ParentFD = FD;
while (ShouldAddDeclsFromParentScope) {
SemaRef.addInstantiatedCapturesToScope(FD, FDPattern, Scope, MLTAL);

ParentFD =
dyn_cast<FunctionDecl>(getLambdaAwareParentOfDeclContext(ParentFD));
Pattern =
dyn_cast<FunctionDecl>(getLambdaAwareParentOfDeclContext(Pattern));
if (!ShouldAddDeclsFromParentScope)
return;

if (!ParentFD || !Pattern)
break;
llvm::SmallVector<std::pair<FunctionDecl *, FunctionDecl *>, 4>
ParentInstantiations;
while (true) {
FDPattern =
dyn_cast<FunctionDecl>(getLambdaAwareParentOfDeclContext(FDPattern));
FD = dyn_cast<FunctionDecl>(getLambdaAwareParentOfDeclContext(FD));

SemaRef.addInstantiatedParametersToScope(ParentFD, Pattern, Scope, MLTAL);
SemaRef.addInstantiatedLocalVarsToScope(ParentFD, Pattern, Scope);
}
if (!FDPattern || !FD)
break;

ParentInstantiations.emplace_back(FDPattern, FD);
}

// Add instantiated parameters and local vars to scopes, starting from the
// outermost lambda to the innermost lambda. This ordering ensures that
// parameters in inner lambdas can correctly depend on those defined
// in outer lambdas, e.g. auto L = [](auto... x) {
// return [](decltype(x)... y) { }; // `y` depends on `x`
// };

for (const auto &[FDPattern, FD] : llvm::reverse(ParentInstantiations)) {
SemaRef.addInstantiatedParametersToScope(FD, FDPattern, Scope, MLTAL);
SemaRef.addInstantiatedLocalVarsToScope(FD, FDPattern, Scope);
}
}
998 changes: 83 additions & 915 deletions clang/lib/Sema/SemaOpenMP.cpp

Large diffs are not rendered by default.

172 changes: 156 additions & 16 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2178,23 +2178,110 @@ namespace {
class ExtractTypeForDeductionGuide
: public TreeTransform<ExtractTypeForDeductionGuide> {
llvm::SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs;
ClassTemplateDecl *NestedPattern;
const MultiLevelTemplateArgumentList *OuterInstantiationArgs;
std::optional<TemplateDeclInstantiator> TypedefNameInstantiator;

public:
typedef TreeTransform<ExtractTypeForDeductionGuide> Base;
ExtractTypeForDeductionGuide(
Sema &SemaRef,
llvm::SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs)
: Base(SemaRef), MaterializedTypedefs(MaterializedTypedefs) {}
llvm::SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs,
ClassTemplateDecl *NestedPattern,
const MultiLevelTemplateArgumentList *OuterInstantiationArgs)
: Base(SemaRef), MaterializedTypedefs(MaterializedTypedefs),
NestedPattern(NestedPattern),
OuterInstantiationArgs(OuterInstantiationArgs) {
if (OuterInstantiationArgs)
TypedefNameInstantiator.emplace(
SemaRef, SemaRef.getASTContext().getTranslationUnitDecl(),
*OuterInstantiationArgs);
}

TypeSourceInfo *transform(TypeSourceInfo *TSI) { return TransformType(TSI); }

/// Returns true if it's safe to substitute \p Typedef with
/// \p OuterInstantiationArgs.
bool mightReferToOuterTemplateParameters(TypedefNameDecl *Typedef) {
if (!NestedPattern)
return false;

static auto WalkUp = [](DeclContext *DC, DeclContext *TargetDC) {
if (DC->Equals(TargetDC))
return true;
while (DC->isRecord()) {
if (DC->Equals(TargetDC))
return true;
DC = DC->getParent();
}
return false;
};

if (WalkUp(Typedef->getDeclContext(), NestedPattern->getTemplatedDecl()))
return true;
if (WalkUp(NestedPattern->getTemplatedDecl(), Typedef->getDeclContext()))
return true;
return false;
}

QualType
RebuildTemplateSpecializationType(TemplateName Template,
SourceLocation TemplateNameLoc,
TemplateArgumentListInfo &TemplateArgs) {
if (!OuterInstantiationArgs ||
!isa_and_present<TypeAliasTemplateDecl>(Template.getAsTemplateDecl()))
return Base::RebuildTemplateSpecializationType(Template, TemplateNameLoc,
TemplateArgs);

auto *TATD = cast<TypeAliasTemplateDecl>(Template.getAsTemplateDecl());
auto *Pattern = TATD;
while (Pattern->getInstantiatedFromMemberTemplate())
Pattern = Pattern->getInstantiatedFromMemberTemplate();
if (!mightReferToOuterTemplateParameters(Pattern->getTemplatedDecl()))
return Base::RebuildTemplateSpecializationType(Template, TemplateNameLoc,
TemplateArgs);

Decl *NewD =
TypedefNameInstantiator->InstantiateTypeAliasTemplateDecl(TATD);
if (!NewD)
return QualType();

auto *NewTATD = cast<TypeAliasTemplateDecl>(NewD);
MaterializedTypedefs.push_back(NewTATD->getTemplatedDecl());

return Base::RebuildTemplateSpecializationType(
TemplateName(NewTATD), TemplateNameLoc, TemplateArgs);
}

QualType TransformTypedefType(TypeLocBuilder &TLB, TypedefTypeLoc TL) {
ASTContext &Context = SemaRef.getASTContext();
TypedefNameDecl *OrigDecl = TL.getTypedefNameDecl();
TypedefNameDecl *Decl = OrigDecl;
// Transform the underlying type of the typedef and clone the Decl only if
// the typedef has a dependent context.
if (OrigDecl->getDeclContext()->isDependentContext()) {
bool InDependentContext = OrigDecl->getDeclContext()->isDependentContext();

// A typedef/alias Decl within the NestedPattern may reference the outer
// template parameters. They're substituted with corresponding instantiation
// arguments here and in RebuildTemplateSpecializationType() above.
// Otherwise, we would have a CTAD guide with "dangling" template
// parameters.
// For example,
// template <class T> struct Outer {
// using Alias = S<T>;
// template <class U> struct Inner {
// Inner(Alias);
// };
// };
if (OuterInstantiationArgs && InDependentContext &&
TL.getTypePtr()->isInstantiationDependentType()) {
Decl = cast_if_present<TypedefNameDecl>(
TypedefNameInstantiator->InstantiateTypedefNameDecl(
OrigDecl, /*IsTypeAlias=*/isa<TypeAliasDecl>(OrigDecl)));
if (!Decl)
return QualType();
MaterializedTypedefs.push_back(Decl);
} else if (InDependentContext) {
TypeLocBuilder InnerTLB;
QualType Transformed =
TransformType(InnerTLB, OrigDecl->getTypeSourceInfo()->getTypeLoc());
Expand All @@ -2220,8 +2307,12 @@ class ExtractTypeForDeductionGuide
}
};

// Build a deduction guide with the specified parameter types.
FunctionTemplateDecl *buildDeductionGuide(
// Build a deduction guide using the provided information.
//
// A deduction guide can be either a template or a non-template function
// declaration. If \p TemplateParams is null, a non-template function
// declaration will be created.
NamedDecl *buildDeductionGuide(
Sema &SemaRef, TemplateDecl *OriginalTemplate,
TemplateParameterList *TemplateParams, CXXConstructorDecl *Ctor,
ExplicitSpecifier ES, TypeSourceInfo *TInfo, SourceLocation LocStart,
Expand All @@ -2247,16 +2338,21 @@ FunctionTemplateDecl *buildDeductionGuide(
Param->setDeclContext(Guide);
for (auto *TD : MaterializedTypedefs)
TD->setDeclContext(Guide);
if (isa<CXXRecordDecl>(DC))
Guide->setAccess(AS_public);

if (!TemplateParams) {
DC->addDecl(Guide);
return Guide;
}

auto *GuideTemplate = FunctionTemplateDecl::Create(
SemaRef.Context, DC, Loc, DeductionGuideName, TemplateParams, Guide);
GuideTemplate->setImplicit(IsImplicit);
Guide->setDescribedFunctionTemplate(GuideTemplate);

if (isa<CXXRecordDecl>(DC)) {
Guide->setAccess(AS_public);
if (isa<CXXRecordDecl>(DC))
GuideTemplate->setAccess(AS_public);
}

DC->addDecl(GuideTemplate);
return GuideTemplate;
Expand Down Expand Up @@ -2541,16 +2637,18 @@ struct ConvertConstructorToDeductionGuideTransform {
// defined outside of the surrounding class template. That is T in the
// above example.
if (NestedPattern) {
NewParam = transformFunctionTypeParam(NewParam, OuterInstantiationArgs,
MaterializedTypedefs);
NewParam = transformFunctionTypeParam(
NewParam, OuterInstantiationArgs, MaterializedTypedefs,
/*TransformingOuterPatterns=*/true);
if (!NewParam)
return QualType();
}
// Then, transform all the references to template parameters that are
// defined at the class template and the constructor. In this example,
// they're U and V, respectively.
NewParam =
transformFunctionTypeParam(NewParam, Args, MaterializedTypedefs);
transformFunctionTypeParam(NewParam, Args, MaterializedTypedefs,
/*TransformingOuterPatterns=*/false);
if (!NewParam)
return QualType();
ParamTypes.push_back(NewParam->getType());
Expand Down Expand Up @@ -2594,7 +2692,8 @@ struct ConvertConstructorToDeductionGuideTransform {

ParmVarDecl *transformFunctionTypeParam(
ParmVarDecl *OldParam, MultiLevelTemplateArgumentList &Args,
llvm::SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs) {
llvm::SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs,
bool TransformingOuterPatterns) {
TypeSourceInfo *OldDI = OldParam->getTypeSourceInfo();
TypeSourceInfo *NewDI;
if (auto PackTL = OldDI->getTypeLoc().getAs<PackExpansionTypeLoc>()) {
Expand All @@ -2617,7 +2716,9 @@ struct ConvertConstructorToDeductionGuideTransform {
// members of the current instantiations with the definitions of those
// typedefs, avoiding triggering instantiation of the deduced type during
// deduction.
NewDI = ExtractTypeForDeductionGuide(SemaRef, MaterializedTypedefs)
NewDI = ExtractTypeForDeductionGuide(
SemaRef, MaterializedTypedefs, NestedPattern,
TransformingOuterPatterns ? &Args : nullptr)
.transform(NewDI);

// Resolving a wording defect, we also inherit default arguments from the
Expand Down Expand Up @@ -2898,7 +2999,8 @@ Expr *buildIsDeducibleConstraint(Sema &SemaRef,
ASTContext &Context = SemaRef.Context;
// Constraint AST nodes must use uninstantiated depth.
if (auto *PrimaryTemplate =
AliasTemplate->getInstantiatedFromMemberTemplate()) {
AliasTemplate->getInstantiatedFromMemberTemplate();
PrimaryTemplate && TemplateParams.size() > 0) {
LocalInstantiationScope Scope(SemaRef);

// Adjust the depth for TemplateParams.
Expand Down Expand Up @@ -3162,12 +3264,12 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
FPrimeTemplateParams,
AliasTemplate->getTemplateParameters()->getRAngleLoc(),
/*RequiresClause=*/RequiresClause);
FunctionTemplateDecl *Result = buildDeductionGuide(
auto *Result = cast<FunctionTemplateDecl>(buildDeductionGuide(
SemaRef, AliasTemplate, FPrimeTemplateParamList,
GG->getCorrespondingConstructor(), GG->getExplicitSpecifier(),
GG->getTypeSourceInfo(), AliasTemplate->getBeginLoc(),
AliasTemplate->getLocation(), AliasTemplate->getEndLoc(),
F->isImplicit());
F->isImplicit()));
cast<CXXDeductionGuideDecl>(Result->getTemplatedDecl())
->setDeductionCandidateKind(GG->getDeductionCandidateKind());
return Result;
Expand Down Expand Up @@ -3198,6 +3300,44 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
Guides.suppressDiagnostics();

for (auto *G : Guides) {
if (auto *DG = dyn_cast<CXXDeductionGuideDecl>(G)) {
// The deduction guide is a non-template function decl, we just clone it.
auto *FunctionType =
SemaRef.Context.getTrivialTypeSourceInfo(DG->getType());
FunctionProtoTypeLoc FPTL =
FunctionType->getTypeLoc().castAs<FunctionProtoTypeLoc>();

// Clone the parameters.
for (unsigned I = 0, N = DG->getNumParams(); I != N; ++I) {
const auto *P = DG->getParamDecl(I);
auto *TSI = SemaRef.Context.getTrivialTypeSourceInfo(P->getType());
ParmVarDecl *NewParam = ParmVarDecl::Create(
SemaRef.Context, G->getDeclContext(),
DG->getParamDecl(I)->getBeginLoc(), P->getLocation(), nullptr,
TSI->getType(), TSI, SC_None, nullptr);
NewParam->setScopeInfo(0, I);
FPTL.setParam(I, NewParam);
}
auto *Transformed = cast<FunctionDecl>(buildDeductionGuide(
SemaRef, AliasTemplate, /*TemplateParams=*/nullptr,
/*Constructor=*/nullptr, DG->getExplicitSpecifier(), FunctionType,
AliasTemplate->getBeginLoc(), AliasTemplate->getLocation(),
AliasTemplate->getEndLoc(), DG->isImplicit()));

// FIXME: Here the synthesized deduction guide is not a templated
// function. Per [dcl.decl]p4, the requires-clause shall be present only
// if the declarator declares a templated function, a bug in standard?
auto *Constraint = buildIsDeducibleConstraint(
SemaRef, AliasTemplate, Transformed->getReturnType(), {});
if (auto *RC = DG->getTrailingRequiresClause()) {
auto Conjunction =
SemaRef.BuildBinOp(SemaRef.getCurScope(), SourceLocation{},
BinaryOperatorKind::BO_LAnd, RC, Constraint);
if (!Conjunction.isInvalid())
Constraint = Conjunction.getAs<Expr>();
}
Transformed->setTrailingRequiresClause(Constraint);
}
FunctionTemplateDecl *F = dyn_cast<FunctionTemplateDecl>(G);
if (!F)
continue;
Expand Down
17 changes: 14 additions & 3 deletions clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1096,8 +1096,8 @@ Decl *TemplateDeclInstantiator::VisitTypeAliasDecl(TypeAliasDecl *D) {
return Typedef;
}

Decl *
TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
Decl *TemplateDeclInstantiator::InstantiateTypeAliasTemplateDecl(
TypeAliasTemplateDecl *D) {
// Create a local instantiation scope for this type alias template, which
// will contain the instantiations of the template parameters.
LocalInstantiationScope Scope(SemaRef);
Expand Down Expand Up @@ -1143,7 +1143,14 @@ TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
if (!PrevAliasTemplate)
Inst->setInstantiatedFromMemberTemplate(D);

Owner->addDecl(Inst);
return Inst;
}

Decl *
TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
Decl *Inst = InstantiateTypeAliasTemplateDecl(D);
if (Inst)
Owner->addDecl(Inst);

return Inst;
}
Expand Down Expand Up @@ -3413,6 +3420,10 @@ Decl *TemplateDeclInstantiator::VisitUsingEnumDecl(UsingEnumDecl *D) {

TypeSourceInfo *TSI = SemaRef.SubstType(D->getEnumType(), TemplateArgs,
D->getLocation(), D->getDeclName());

if (!TSI)
return nullptr;

UsingEnumDecl *NewUD =
UsingEnumDecl::Create(SemaRef.Context, Owner, D->getUsingLoc(),
D->getEnumLoc(), D->getLocation(), TSI);
Expand Down
8 changes: 5 additions & 3 deletions clang/lib/Sema/SemaType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9324,15 +9324,17 @@ BuildTypeCoupledDecls(Expr *E,
}

QualType Sema::BuildCountAttributedArrayOrPointerType(QualType WrappedTy,
Expr *CountExpr) {
Expr *CountExpr,
bool CountInBytes,
bool OrNull) {
assert(WrappedTy->isIncompleteArrayType() || WrappedTy->isPointerType());

llvm::SmallVector<TypeCoupledDeclRefInfo, 1> Decls;
BuildTypeCoupledDecls(CountExpr, Decls);
/// When the resulting expression is invalid, we still create the AST using
/// the original count expression for the sake of AST dump.
return Context.getCountAttributedType(
WrappedTy, CountExpr, /*CountInBytes*/ false, /*OrNull*/ false, Decls);
return Context.getCountAttributedType(WrappedTy, CountExpr, CountInBytes,
OrNull, Decls);
}

/// getDecltypeForExpr - Given an expr, will return the decltype for
Expand Down
6 changes: 5 additions & 1 deletion clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -2896,6 +2896,9 @@ class TreeTransform {
SS.Adopt(QualifierLoc);

Base = BaseResult.get();
if (Base->containsErrors())
return ExprError();

QualType BaseType = Base->getType();

if (isArrow && !BaseType->isPointerType())
Expand Down Expand Up @@ -7394,7 +7397,8 @@ QualType TreeTransform<Derived>::TransformCountAttributedType(
if (getDerived().AlwaysRebuild() || InnerTy != OldTy->desugar() ||
OldCount != NewCount) {
// Currently, CountAttributedType can only wrap incomplete array types.
Result = SemaRef.BuildCountAttributedArrayOrPointerType(InnerTy, NewCount);
Result = SemaRef.BuildCountAttributedArrayOrPointerType(
InnerTy, NewCount, OldTy->isCountInBytes(), OldTy->isOrNull());
}

TLB.push<CountAttributedTypeLoc>(Result);
Expand Down
11 changes: 0 additions & 11 deletions clang/lib/Serialization/ASTReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3921,13 +3921,6 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
}
break;

case VTABLES_TO_EMIT:
if (F.Kind == MK_MainFile ||
getContext().getLangOpts().BuildingPCHWithObjectFile)
for (unsigned I = 0, N = Record.size(); I != N; /*in loop*/)
VTablesToEmit.push_back(ReadDeclID(F, Record, I));
break;

case IMPORTED_MODULES:
if (!F.isModule()) {
// If we aren't loading a module (which has its own exports), make
Expand Down Expand Up @@ -8117,10 +8110,6 @@ void ASTReader::PassInterestingDeclToConsumer(Decl *D) {
Consumer->HandleInterestingDecl(DeclGroupRef(D));
}

void ASTReader::PassVTableToConsumer(CXXRecordDecl *RD) {
Consumer->HandleVTable(RD);
}

void ASTReader::StartTranslationUnit(ASTConsumer *Consumer) {
this->Consumer = Consumer;

Expand Down
7 changes: 0 additions & 7 deletions clang/lib/Serialization/ASTReaderDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4235,13 +4235,6 @@ void ASTReader::PassInterestingDeclsToConsumer() {

// If we add any new potential interesting decl in the last call, consume it.
ConsumingPotentialInterestingDecls();

for (GlobalDeclID ID : VTablesToEmit) {
auto *RD = cast<CXXRecordDecl>(GetDecl(ID));
assert(!RD->shouldEmitInExternalSource());
PassVTableToConsumer(RD);
}
VTablesToEmit.clear();
}

void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) {
Expand Down
33 changes: 4 additions & 29 deletions clang/lib/Serialization/ASTWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -927,7 +927,6 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(DECLS_TO_CHECK_FOR_DEFERRED_DIAGS);
RECORD(PP_ASSUME_NONNULL_LOC);
RECORD(PP_UNSAFE_BUFFER_USAGE);
RECORD(VTABLES_TO_EMIT);

// SourceManager Block.
BLOCK(SOURCE_MANAGER_BLOCK);
Expand Down Expand Up @@ -3962,10 +3961,6 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP,
Stream.EmitRecord(INTERESTING_IDENTIFIERS, InterestingIdents);
}

void ASTWriter::handleVTable(CXXRecordDecl *RD) {
PendingEmittingVTables.push_back(RD);
}

//===----------------------------------------------------------------------===//
// DeclContext's Name Lookup Table Serialization
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -5168,13 +5163,6 @@ void ASTWriter::PrepareWritingSpecialDecls(Sema &SemaRef) {
// Write all of the DeclsToCheckForDeferredDiags.
for (auto *D : SemaRef.DeclsToCheckForDeferredDiags)
GetDeclRef(D);

// Write all classes need to emit the vtable definitions if required.
if (isWritingStdCXXNamedModules())
for (CXXRecordDecl *RD : PendingEmittingVTables)
GetDeclRef(RD);
else
PendingEmittingVTables.clear();
}

void ASTWriter::WriteSpecialDeclRecords(Sema &SemaRef) {
Expand Down Expand Up @@ -5329,17 +5317,6 @@ void ASTWriter::WriteSpecialDeclRecords(Sema &SemaRef) {
}
if (!DeleteExprsToAnalyze.empty())
Stream.EmitRecord(DELETE_EXPRS_TO_ANALYZE, DeleteExprsToAnalyze);

RecordData VTablesToEmit;
for (CXXRecordDecl *RD : PendingEmittingVTables) {
if (!wasDeclEmitted(RD))
continue;

AddDeclRef(RD, VTablesToEmit);
}

if (!VTablesToEmit.empty())
Stream.EmitRecord(VTABLES_TO_EMIT, VTablesToEmit);
}

ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
Expand Down Expand Up @@ -6587,12 +6564,10 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) {
// computed.
Record->push_back(D->getODRHash());

bool ModulesCodegen =
!D->isDependentType() &&
(Writer->Context->getLangOpts().ModulesDebugInfo ||
D->isInNamedModule());
Record->push_back(ModulesCodegen);
if (ModulesCodegen)
bool ModulesDebugInfo =
Writer->Context->getLangOpts().ModulesDebugInfo && !D->isDependentType();
Record->push_back(ModulesDebugInfo);
if (ModulesDebugInfo)
Writer->AddDeclRef(D, Writer->ModularCodegenDecls);

// IsLambda bit is already saved.
Expand Down
6 changes: 0 additions & 6 deletions clang/lib/Serialization/ASTWriterDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1537,14 +1537,8 @@ void ASTDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) {
if (D->isThisDeclarationADefinition())
Record.AddCXXDefinitionData(D);

if (D->isCompleteDefinition() && D->isInNamedModule())
Writer.AddDeclRef(D, Writer.ModularCodegenDecls);

// Store (what we currently believe to be) the key function to avoid
// deserializing every method so we can compute it.
//
// FIXME: Avoid adding the key function if the class is defined in
// module purview since the key function is meaningless in module purview.
if (D->isCompleteDefinition())
Record.AddDeclRef(Context.getCurrentKeyFunction(D));

Expand Down
28 changes: 22 additions & 6 deletions clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/YAMLTraits.h"

#include <limits>
Expand Down Expand Up @@ -391,9 +392,10 @@ class GenericTaintChecker : public Checker<check::PreCall, check::PostCall> {
bool generateReportIfTainted(const Expr *E, StringRef Msg,
CheckerContext &C) const;

private:
const BugType BT{this, "Use of Untrusted Data", categories::TaintedData};
bool isTaintReporterCheckerEnabled = false;
std::optional<BugType> BT;

private:
bool checkUncontrolledFormatString(const CallEvent &Call,
CheckerContext &C) const;

Expand Down Expand Up @@ -1033,20 +1035,23 @@ bool GenericTaintRule::UntrustedEnv(CheckerContext &C) {
bool GenericTaintChecker::generateReportIfTainted(const Expr *E, StringRef Msg,
CheckerContext &C) const {
assert(E);
if (!isTaintReporterCheckerEnabled)
return false;
std::optional<SVal> TaintedSVal =
getTaintedPointeeOrPointer(C.getState(), C.getSVal(E));

if (!TaintedSVal)
return false;

// Generate diagnostic.
if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
auto report = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);
assert(BT);
static CheckerProgramPointTag Tag(BT->getCheckerName(), Msg);
if (ExplodedNode *N = C.generateNonFatalErrorNode(C.getState(), &Tag)) {
auto report = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N);
report->addRange(E->getSourceRange());
for (auto TaintedSym : getTaintedSymbols(C.getState(), *TaintedSVal)) {
report->markInteresting(TaintedSym);
}

C.emitReport(std::move(report));
return true;
}
Expand Down Expand Up @@ -1122,10 +1127,21 @@ void GenericTaintChecker::taintUnsafeSocketProtocol(const CallEvent &Call,
}

/// Checker registration
void ento::registerGenericTaintChecker(CheckerManager &Mgr) {
void ento::registerTaintPropagationChecker(CheckerManager &Mgr) {
Mgr.registerChecker<GenericTaintChecker>();
}

bool ento::shouldRegisterTaintPropagationChecker(const CheckerManager &mgr) {
return true;
}

void ento::registerGenericTaintChecker(CheckerManager &Mgr) {
GenericTaintChecker *checker = Mgr.getChecker<GenericTaintChecker>();
checker->isTaintReporterCheckerEnabled = true;
checker->BT.emplace(Mgr.getCurrentCheckerName(), "Use of Untrusted Data",
categories::TaintedData);
}

bool ento::shouldRegisterGenericTaintChecker(const CheckerManager &mgr) {
return true;
}
10 changes: 8 additions & 2 deletions clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2057,11 +2057,17 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
llvm_unreachable("Support for MatrixSubscriptExpr is not implemented.");
break;

case Stmt::GCCAsmStmtClass:
case Stmt::GCCAsmStmtClass: {
Bldr.takeNodes(Pred);
VisitGCCAsmStmt(cast<GCCAsmStmt>(S), Pred, Dst);
ExplodedNodeSet PreVisit;
getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this);
ExplodedNodeSet PostVisit;
for (ExplodedNode *const N : PreVisit)
VisitGCCAsmStmt(cast<GCCAsmStmt>(S), N, PostVisit);
getCheckerManager().runCheckersForPostStmt(Dst, PostVisit, S, *this);
Bldr.addNodes(Dst);
break;
}

case Stmt::MSAsmStmtClass:
Bldr.takeNodes(Pred);
Expand Down
45 changes: 45 additions & 0 deletions clang/test/AST/attr-counted-by-or-null-late-parsed-struct-ptrs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// RUN: %clang_cc1 -fexperimental-late-parse-attributes %s -ast-dump | FileCheck %s

#define __counted_by_or_null(f) __attribute__((counted_by_or_null(f)))

struct size_known {
int field;
};

//==============================================================================
// __counted_by_or_null on struct member pointer in decl attribute position
//==============================================================================

struct on_member_pointer_complete_ty {
struct size_known *buf __counted_by_or_null(count);
int count;
};
// CHECK-LABEL: struct on_member_pointer_complete_ty definition
// CHECK-NEXT: |-FieldDecl {{.*}} buf 'struct size_known * __counted_by_or_null(count)':'struct size_known *'
// CHECK-NEXT: `-FieldDecl {{.*}} referenced count 'int'

struct on_pointer_anon_count {
struct size_known *buf __counted_by_or_null(count);
struct {
int count;
};
};

// CHECK-LABEL: struct on_pointer_anon_count definition
// CHECK-NEXT: |-FieldDecl {{.*}} buf 'struct size_known * __counted_by_or_null(count)':'struct size_known *'
// CHECK-NEXT: |-RecordDecl {{.*}} struct definition
// CHECK-NEXT: | `-FieldDecl {{.*}} count 'int'
// CHECK-NEXT: |-FieldDecl {{.*}} implicit 'struct on_pointer_anon_count::(anonymous at {{.*}})'
// CHECK-NEXT: `-IndirectFieldDecl {{.*}} implicit referenced count 'int'
// CHECK-NEXT: |-Field {{.*}} '' 'struct on_pointer_anon_count::(anonymous at {{.*}})'
// CHECK-NEXT: `-Field {{.*}} 'count' 'int'

//==============================================================================
// __counted_by_or_null on struct member pointer in type attribute position
//==============================================================================
// TODO: Correctly parse counted_by_or_null as a type attribute. Currently it is parsed
// as a declaration attribute and is **not** late parsed resulting in the `count`
// field being unavailable.
//
// See `clang/test/Sema/attr-counted-by-late-parsed-struct-ptrs.c` for test
// cases.
117 changes: 117 additions & 0 deletions clang/test/AST/attr-counted-by-or-null-struct-ptrs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// RUN: %clang_cc1 %s -ast-dump | FileCheck %s

#define __counted_by_or_null(f) __attribute__((counted_by_or_null(f)))

struct size_unknown;
struct size_known {
int field;
};

//==============================================================================
// __counted_by_or_null on struct member pointer in decl attribute position
//==============================================================================

// CHECK-LABEL: RecordDecl {{.+}} struct on_member_pointer_complete_ty definition
// CHECK-NEXT: |-FieldDecl {{.+}} referenced count 'int'
// CHECK-NEXT: `-FieldDecl {{.+}} buf 'struct size_known * __counted_by_or_null(count)':'struct size_known *'
struct on_member_pointer_complete_ty {
int count;
struct size_known * buf __counted_by_or_null(count);
};

// CHECK-LABEL: RecordDecl {{.+}} struct on_pointer_anon_buf definition
// CHECK-NEXT: |-FieldDecl {{.+}} referenced count 'int'
// CHECK-NEXT: |-RecordDecl {{.+}} struct definition
// CHECK-NEXT: | `-FieldDecl {{.+}} buf 'struct size_known * __counted_by_or_null(count)':'struct size_known *'
// CHECK-NEXT: |-FieldDecl {{.+}} implicit 'struct on_pointer_anon_buf::(anonymous at [[ANON_STRUCT_PATH:.+]])'
// CHECK-NEXT: `-IndirectFieldDecl {{.+}} implicit buf 'struct size_known * __counted_by_or_null(count)':'struct size_known *'
// CHECK-NEXT: |-Field {{.+}} '' 'struct on_pointer_anon_buf::(anonymous at [[ANON_STRUCT_PATH]])'
// CHECK-NEXT: `-Field {{.+}} 'buf' 'struct size_known * __counted_by_or_null(count)':'struct size_known *'
struct on_pointer_anon_buf {
int count;
struct {
struct size_known *buf __counted_by_or_null(count);
};
};

struct on_pointer_anon_count {
struct {
int count;
};
struct size_known *buf __counted_by_or_null(count);
};

//==============================================================================
// __counted_by_or_null on struct member pointer in type attribute position
//==============================================================================
// TODO: Correctly parse counted_by_or_null as a type attribute. Currently it is parsed
// as a declaration attribute

// CHECK-LABEL: RecordDecl {{.+}} struct on_member_pointer_complete_ty_ty_pos definition
// CHECK-NEXT: |-FieldDecl {{.+}} referenced count 'int'
// CHECK-NEXT: `-FieldDecl {{.+}} buf 'struct size_known * __counted_by_or_null(count)':'struct size_known *'
struct on_member_pointer_complete_ty_ty_pos {
int count;
struct size_known *__counted_by_or_null(count) buf;
};

// TODO: This should be forbidden but isn't due to counted_by_or_null being treated as a
// declaration attribute. The attribute ends up on the outer most pointer
// (allowed by sema) even though syntactically its supposed to be on the inner
// pointer (would not allowed by sema due to pointee being a function type).
// CHECK-LABEL: RecordDecl {{.+}} struct on_member_pointer_fn_ptr_ty_ty_pos_inner definition
// CHECK-NEXT: |-FieldDecl {{.+}} referenced count 'int'
// CHECK-NEXT: `-FieldDecl {{.+}} fn_ptr 'void (** __counted_by_or_null(count))(void)':'void (**)(void)'
struct on_member_pointer_fn_ptr_ty_ty_pos_inner {
int count;
void (* __counted_by_or_null(count) * fn_ptr)(void);
};

// FIXME: The generated AST here is wrong. The attribute should be on the inner
// pointer.
// CHECK-LABEL: RecordDecl {{.+}} struct on_nested_pointer_inner definition
// CHECK-NEXT: |-FieldDecl {{.+}} referenced count 'int'
// CHECK-NEXT: `-FieldDecl {{.+}} buf 'struct size_known ** __counted_by_or_null(count)':'struct size_known **'
struct on_nested_pointer_inner {
int count;
// TODO: This should be disallowed because in the `-fbounds-safety` model
// `__counted_by_or_null` can only be nested when used in function parameters.
struct size_known *__counted_by_or_null(count) *buf;
};

// CHECK-LABEL: RecordDecl {{.+}} struct on_nested_pointer_outer definition
// CHECK-NEXT: |-FieldDecl {{.+}} referenced count 'int'
// CHECK-NEXT: `-FieldDecl {{.+}} buf 'struct size_known ** __counted_by_or_null(count)':'struct size_known **'
struct on_nested_pointer_outer {
int count;
struct size_known **__counted_by_or_null(count) buf;
};

// CHECK-LABEL: RecordDecl {{.+}} struct on_pointer_anon_buf_ty_pos definition
// CHECK-NEXT: |-FieldDecl {{.+}} referenced count 'int'
// CHECK-NEXT: |-RecordDecl {{.+}} struct definition
// CHECK-NEXT: | `-FieldDecl {{.+}} buf 'struct size_known * __counted_by_or_null(count)':'struct size_known *'
// CHECK-NEXT: |-FieldDecl {{.+}} implicit 'struct on_pointer_anon_buf_ty_pos::(anonymous at [[ANON_STRUCT_PATH2:.+]])'
// CHECK-NEXT: `-IndirectFieldDecl {{.+}} implicit buf 'struct size_known * __counted_by_or_null(count)':'struct size_known *'
// CHECK-NEXT: |-Field {{.+}} '' 'struct on_pointer_anon_buf_ty_pos::(anonymous at [[ANON_STRUCT_PATH2]])'
// CHECK-NEXT: `-Field {{.+}} 'buf' 'struct size_known * __counted_by_or_null(count)':'struct size_known *'
struct on_pointer_anon_buf_ty_pos {
int count;
struct {
struct size_known * __counted_by_or_null(count) buf;
};
};

// CHECK-LABEL: RecordDecl {{.+}} struct on_pointer_anon_count_ty_pos definition
// CHECK-NEXT: |-RecordDecl {{.+}} struct definition
// CHECK-NEXT: | `-FieldDecl {{.+}} count 'int'
// CHECK-NEXT: |-FieldDecl {{.+}} implicit 'struct on_pointer_anon_count_ty_pos::(anonymous at [[ANON_STRUCT_PATH3:.+]])'
// CHECK-NEXT: |-IndirectFieldDecl {{.+}} implicit referenced count 'int'
// CHECK-NEXT: | |-Field {{.+}} '' 'struct on_pointer_anon_count_ty_pos::(anonymous at [[ANON_STRUCT_PATH3]])'
// CHECK-NEXT: | `-Field {{.+}} 'count' 'int'
struct on_pointer_anon_count_ty_pos {
struct {
int count;
};
struct size_known *__counted_by_or_null(count) buf;
};
45 changes: 45 additions & 0 deletions clang/test/AST/attr-sized-by-late-parsed-struct-ptrs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// RUN: %clang_cc1 -fexperimental-late-parse-attributes %s -ast-dump | FileCheck %s

#define __sized_by(f) __attribute__((sized_by(f)))

struct size_known {
int field;
};

//==============================================================================
// __sized_by on struct member pointer in decl attribute position
//==============================================================================

struct on_member_pointer_complete_ty {
struct size_known *buf __sized_by(count);
int count;
};
// CHECK-LABEL: struct on_member_pointer_complete_ty definition
// CHECK-NEXT: |-FieldDecl {{.*}} buf 'struct size_known * __sized_by(count)':'struct size_known *'
// CHECK-NEXT: `-FieldDecl {{.*}} referenced count 'int'

struct on_pointer_anon_count {
struct size_known *buf __sized_by(count);
struct {
int count;
};
};

// CHECK-LABEL: struct on_pointer_anon_count definition
// CHECK-NEXT: |-FieldDecl {{.*}} buf 'struct size_known * __sized_by(count)':'struct size_known *'
// CHECK-NEXT: |-RecordDecl {{.*}} struct definition
// CHECK-NEXT: | `-FieldDecl {{.*}} count 'int'
// CHECK-NEXT: |-FieldDecl {{.*}} implicit 'struct on_pointer_anon_count::(anonymous at {{.*}})'
// CHECK-NEXT: `-IndirectFieldDecl {{.*}} implicit referenced count 'int'
// CHECK-NEXT: |-Field {{.*}} '' 'struct on_pointer_anon_count::(anonymous at {{.*}})'
// CHECK-NEXT: `-Field {{.*}} 'count' 'int'

//==============================================================================
// __sized_by on struct member pointer in type attribute position
//==============================================================================
// TODO: Correctly parse sized_by as a type attribute. Currently it is parsed
// as a declaration attribute and is **not** late parsed resulting in the `count`
// field being unavailable.
//
// See `clang/test/Sema/attr-counted-by-late-parsed-struct-ptrs.c` for test
// cases.
45 changes: 45 additions & 0 deletions clang/test/AST/attr-sized-by-or-null-late-parsed-struct-ptrs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// RUN: %clang_cc1 -fexperimental-late-parse-attributes %s -ast-dump | FileCheck %s

#define __sized_by_or_null(f) __attribute__((sized_by_or_null(f)))

struct size_known {
int field;
};

//==============================================================================
// __sized_by_or_null on struct member pointer in decl attribute position
//==============================================================================

struct on_member_pointer_complete_ty {
struct size_known *buf __sized_by_or_null(count);
int count;
};
// CHECK-LABEL: struct on_member_pointer_complete_ty definition
// CHECK-NEXT: |-FieldDecl {{.*}} buf 'struct size_known * __sized_by_or_null(count)':'struct size_known *'
// CHECK-NEXT: `-FieldDecl {{.*}} referenced count 'int'

struct on_pointer_anon_count {
struct size_known *buf __sized_by_or_null(count);
struct {
int count;
};
};

// CHECK-LABEL: struct on_pointer_anon_count definition
// CHECK-NEXT: |-FieldDecl {{.*}} buf 'struct size_known * __sized_by_or_null(count)':'struct size_known *'
// CHECK-NEXT: |-RecordDecl {{.*}} struct definition
// CHECK-NEXT: | `-FieldDecl {{.*}} count 'int'
// CHECK-NEXT: |-FieldDecl {{.*}} implicit 'struct on_pointer_anon_count::(anonymous at {{.*}})'
// CHECK-NEXT: `-IndirectFieldDecl {{.*}} implicit referenced count 'int'
// CHECK-NEXT: |-Field {{.*}} '' 'struct on_pointer_anon_count::(anonymous at {{.*}})'
// CHECK-NEXT: `-Field {{.*}} 'count' 'int'

//==============================================================================
// __sized_by_or_null on struct member pointer in type attribute position
//==============================================================================
// TODO: Correctly parse sized_by_or_null as a type attribute. Currently it is parsed
// as a declaration attribute and is **not** late parsed resulting in the `count`
// field being unavailable.
//
// See `clang/test/Sema/attr-counted-by-late-parsed-struct-ptrs.c` for test
// cases.
117 changes: 117 additions & 0 deletions clang/test/AST/attr-sized-by-or-null-struct-ptrs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// RUN: %clang_cc1 %s -ast-dump | FileCheck %s

#define __sized_by_or_null(f) __attribute__((sized_by_or_null(f)))

struct size_unknown;
struct size_known {
int field;
};

//==============================================================================
// __sized_by_or_null on struct member pointer in decl attribute position
//==============================================================================

// CHECK-LABEL: RecordDecl {{.+}} struct on_member_pointer_complete_ty definition
// CHECK-NEXT: |-FieldDecl {{.+}} referenced count 'int'
// CHECK-NEXT: `-FieldDecl {{.+}} buf 'struct size_known * __sized_by_or_null(count)':'struct size_known *'
struct on_member_pointer_complete_ty {
int count;
struct size_known * buf __sized_by_or_null(count);
};

// CHECK-LABEL: RecordDecl {{.+}} struct on_pointer_anon_buf definition
// CHECK-NEXT: |-FieldDecl {{.+}} referenced count 'int'
// CHECK-NEXT: |-RecordDecl {{.+}} struct definition
// CHECK-NEXT: | `-FieldDecl {{.+}} buf 'struct size_known * __sized_by_or_null(count)':'struct size_known *'
// CHECK-NEXT: |-FieldDecl {{.+}} implicit 'struct on_pointer_anon_buf::(anonymous at [[ANON_STRUCT_PATH:.+]])'
// CHECK-NEXT: `-IndirectFieldDecl {{.+}} implicit buf 'struct size_known * __sized_by_or_null(count)':'struct size_known *'
// CHECK-NEXT: |-Field {{.+}} '' 'struct on_pointer_anon_buf::(anonymous at [[ANON_STRUCT_PATH]])'
// CHECK-NEXT: `-Field {{.+}} 'buf' 'struct size_known * __sized_by_or_null(count)':'struct size_known *'
struct on_pointer_anon_buf {
int count;
struct {
struct size_known *buf __sized_by_or_null(count);
};
};

struct on_pointer_anon_count {
struct {
int count;
};
struct size_known *buf __sized_by_or_null(count);
};

//==============================================================================
// __sized_by_or_null on struct member pointer in type attribute position
//==============================================================================
// TODO: Correctly parse sized_by_or_null as a type attribute. Currently it is parsed
// as a declaration attribute

// CHECK-LABEL: RecordDecl {{.+}} struct on_member_pointer_complete_ty_ty_pos definition
// CHECK-NEXT: |-FieldDecl {{.+}} referenced count 'int'
// CHECK-NEXT: `-FieldDecl {{.+}} buf 'struct size_known * __sized_by_or_null(count)':'struct size_known *'
struct on_member_pointer_complete_ty_ty_pos {
int count;
struct size_known *__sized_by_or_null(count) buf;
};

// TODO: This should be forbidden but isn't due to sized_by_or_null being treated as a
// declaration attribute. The attribute ends up on the outer most pointer
// (allowed by sema) even though syntactically its supposed to be on the inner
// pointer (would not allowed by sema due to pointee being a function type).
// CHECK-LABEL: RecordDecl {{.+}} struct on_member_pointer_fn_ptr_ty_ty_pos_inner definition
// CHECK-NEXT: |-FieldDecl {{.+}} referenced count 'int'
// CHECK-NEXT: `-FieldDecl {{.+}} fn_ptr 'void (** __sized_by_or_null(count))(void)':'void (**)(void)'
struct on_member_pointer_fn_ptr_ty_ty_pos_inner {
int count;
void (* __sized_by_or_null(count) * fn_ptr)(void);
};

// FIXME: The generated AST here is wrong. The attribute should be on the inner
// pointer.
// CHECK-LABEL: RecordDecl {{.+}} struct on_nested_pointer_inner definition
// CHECK-NEXT: |-FieldDecl {{.+}} referenced count 'int'
// CHECK-NEXT: `-FieldDecl {{.+}} buf 'struct size_known ** __sized_by_or_null(count)':'struct size_known **'
struct on_nested_pointer_inner {
int count;
// TODO: This should be disallowed because in the `-fbounds-safety` model
// `__sized_by_or_null` can only be nested when used in function parameters.
struct size_known *__sized_by_or_null(count) *buf;
};

// CHECK-LABEL: RecordDecl {{.+}} struct on_nested_pointer_outer definition
// CHECK-NEXT: |-FieldDecl {{.+}} referenced count 'int'
// CHECK-NEXT: `-FieldDecl {{.+}} buf 'struct size_known ** __sized_by_or_null(count)':'struct size_known **'
struct on_nested_pointer_outer {
int count;
struct size_known **__sized_by_or_null(count) buf;
};

// CHECK-LABEL: RecordDecl {{.+}} struct on_pointer_anon_buf_ty_pos definition
// CHECK-NEXT: |-FieldDecl {{.+}} referenced count 'int'
// CHECK-NEXT: |-RecordDecl {{.+}} struct definition
// CHECK-NEXT: | `-FieldDecl {{.+}} buf 'struct size_known * __sized_by_or_null(count)':'struct size_known *'
// CHECK-NEXT: |-FieldDecl {{.+}} implicit 'struct on_pointer_anon_buf_ty_pos::(anonymous at [[ANON_STRUCT_PATH2:.+]])'
// CHECK-NEXT: `-IndirectFieldDecl {{.+}} implicit buf 'struct size_known * __sized_by_or_null(count)':'struct size_known *'
// CHECK-NEXT: |-Field {{.+}} '' 'struct on_pointer_anon_buf_ty_pos::(anonymous at [[ANON_STRUCT_PATH2]])'
// CHECK-NEXT: `-Field {{.+}} 'buf' 'struct size_known * __sized_by_or_null(count)':'struct size_known *'
struct on_pointer_anon_buf_ty_pos {
int count;
struct {
struct size_known * __sized_by_or_null(count) buf;
};
};

// CHECK-LABEL: RecordDecl {{.+}} struct on_pointer_anon_count_ty_pos definition
// CHECK-NEXT: |-RecordDecl {{.+}} struct definition
// CHECK-NEXT: | `-FieldDecl {{.+}} count 'int'
// CHECK-NEXT: |-FieldDecl {{.+}} implicit 'struct on_pointer_anon_count_ty_pos::(anonymous at [[ANON_STRUCT_PATH3:.+]])'
// CHECK-NEXT: |-IndirectFieldDecl {{.+}} implicit referenced count 'int'
// CHECK-NEXT: | |-Field {{.+}} '' 'struct on_pointer_anon_count_ty_pos::(anonymous at [[ANON_STRUCT_PATH3]])'
// CHECK-NEXT: | `-Field {{.+}} 'count' 'int'
struct on_pointer_anon_count_ty_pos {
struct {
int count;
};
struct size_known *__sized_by_or_null(count) buf;
};
117 changes: 117 additions & 0 deletions clang/test/AST/attr-sized-by-struct-ptrs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// RUN: %clang_cc1 %s -ast-dump | FileCheck %s

#define __sized_by(f) __attribute__((sized_by(f)))

struct size_unknown;
struct size_known {
int field;
};

//==============================================================================
// __sized_by on struct member pointer in decl attribute position
//==============================================================================

// CHECK-LABEL: RecordDecl {{.+}} struct on_member_pointer_complete_ty definition
// CHECK-NEXT: |-FieldDecl {{.+}} referenced count 'int'
// CHECK-NEXT: `-FieldDecl {{.+}} buf 'struct size_known * __sized_by(count)':'struct size_known *'
struct on_member_pointer_complete_ty {
int count;
struct size_known * buf __sized_by(count);
};

// CHECK-LABEL: RecordDecl {{.+}} struct on_pointer_anon_buf definition
// CHECK-NEXT: |-FieldDecl {{.+}} referenced count 'int'
// CHECK-NEXT: |-RecordDecl {{.+}} struct definition
// CHECK-NEXT: | `-FieldDecl {{.+}} buf 'struct size_known * __sized_by(count)':'struct size_known *'
// CHECK-NEXT: |-FieldDecl {{.+}} implicit 'struct on_pointer_anon_buf::(anonymous at [[ANON_STRUCT_PATH:.+]])'
// CHECK-NEXT: `-IndirectFieldDecl {{.+}} implicit buf 'struct size_known * __sized_by(count)':'struct size_known *'
// CHECK-NEXT: |-Field {{.+}} '' 'struct on_pointer_anon_buf::(anonymous at [[ANON_STRUCT_PATH]])'
// CHECK-NEXT: `-Field {{.+}} 'buf' 'struct size_known * __sized_by(count)':'struct size_known *'
struct on_pointer_anon_buf {
int count;
struct {
struct size_known *buf __sized_by(count);
};
};

struct on_pointer_anon_count {
struct {
int count;
};
struct size_known *buf __sized_by(count);
};

//==============================================================================
// __sized_by on struct member pointer in type attribute position
//==============================================================================
// TODO: Correctly parse sized_by as a type attribute. Currently it is parsed
// as a declaration attribute

// CHECK-LABEL: RecordDecl {{.+}} struct on_member_pointer_complete_ty_ty_pos definition
// CHECK-NEXT: |-FieldDecl {{.+}} referenced count 'int'
// CHECK-NEXT: `-FieldDecl {{.+}} buf 'struct size_known * __sized_by(count)':'struct size_known *'
struct on_member_pointer_complete_ty_ty_pos {
int count;
struct size_known *__sized_by(count) buf;
};

// TODO: This should be forbidden but isn't due to sized_by being treated as a
// declaration attribute. The attribute ends up on the outer most pointer
// (allowed by sema) even though syntactically its supposed to be on the inner
// pointer (would not allowed by sema due to pointee being a function type).
// CHECK-LABEL: RecordDecl {{.+}} struct on_member_pointer_fn_ptr_ty_ty_pos_inner definition
// CHECK-NEXT: |-FieldDecl {{.+}} referenced count 'int'
// CHECK-NEXT: `-FieldDecl {{.+}} fn_ptr 'void (** __sized_by(count))(void)':'void (**)(void)'
struct on_member_pointer_fn_ptr_ty_ty_pos_inner {
int count;
void (* __sized_by(count) * fn_ptr)(void);
};

// FIXME: The generated AST here is wrong. The attribute should be on the inner
// pointer.
// CHECK-LABEL: RecordDecl {{.+}} struct on_nested_pointer_inner definition
// CHECK-NEXT: |-FieldDecl {{.+}} referenced count 'int'
// CHECK-NEXT: `-FieldDecl {{.+}} buf 'struct size_known ** __sized_by(count)':'struct size_known **'
struct on_nested_pointer_inner {
int count;
// TODO: This should be disallowed because in the `-fbounds-safety` model
// `__sized_by` can only be nested when used in function parameters.
struct size_known *__sized_by(count) *buf;
};

// CHECK-LABEL: RecordDecl {{.+}} struct on_nested_pointer_outer definition
// CHECK-NEXT: |-FieldDecl {{.+}} referenced count 'int'
// CHECK-NEXT: `-FieldDecl {{.+}} buf 'struct size_known ** __sized_by(count)':'struct size_known **'
struct on_nested_pointer_outer {
int count;
struct size_known **__sized_by(count) buf;
};

// CHECK-LABEL: RecordDecl {{.+}} struct on_pointer_anon_buf_ty_pos definition
// CHECK-NEXT: |-FieldDecl {{.+}} referenced count 'int'
// CHECK-NEXT: |-RecordDecl {{.+}} struct definition
// CHECK-NEXT: | `-FieldDecl {{.+}} buf 'struct size_known * __sized_by(count)':'struct size_known *'
// CHECK-NEXT: |-FieldDecl {{.+}} implicit 'struct on_pointer_anon_buf_ty_pos::(anonymous at [[ANON_STRUCT_PATH2:.+]])'
// CHECK-NEXT: `-IndirectFieldDecl {{.+}} implicit buf 'struct size_known * __sized_by(count)':'struct size_known *'
// CHECK-NEXT: |-Field {{.+}} '' 'struct on_pointer_anon_buf_ty_pos::(anonymous at [[ANON_STRUCT_PATH2]])'
// CHECK-NEXT: `-Field {{.+}} 'buf' 'struct size_known * __sized_by(count)':'struct size_known *'
struct on_pointer_anon_buf_ty_pos {
int count;
struct {
struct size_known * __sized_by(count) buf;
};
};

// CHECK-LABEL: RecordDecl {{.+}} struct on_pointer_anon_count_ty_pos definition
// CHECK-NEXT: |-RecordDecl {{.+}} struct definition
// CHECK-NEXT: | `-FieldDecl {{.+}} count 'int'
// CHECK-NEXT: |-FieldDecl {{.+}} implicit 'struct on_pointer_anon_count_ty_pos::(anonymous at [[ANON_STRUCT_PATH3:.+]])'
// CHECK-NEXT: |-IndirectFieldDecl {{.+}} implicit referenced count 'int'
// CHECK-NEXT: | |-Field {{.+}} '' 'struct on_pointer_anon_count_ty_pos::(anonymous at [[ANON_STRUCT_PATH3]])'
// CHECK-NEXT: | `-Field {{.+}} 'count' 'int'
struct on_pointer_anon_count_ty_pos {
struct {
int count;
};
struct size_known *__sized_by(count) buf;
};
1 change: 1 addition & 0 deletions clang/test/C/C23/n3017.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -verify -fsyntax-only --embed-dir=%S/Inputs -std=c2x %s -Wno-constant-logical-operand
// RUN: %clang_cc1 -verify -fsyntax-only --embed-dir=%S/Inputs -std=c2x %s -Wno-constant-logical-operand -fexperimental-new-constant-interpreter

/* WG14 N3017: full
* #embed - a scannable, tooling-friendly binary resource inclusion mechanism
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// RUN: %clang_cc1 -verify -Wno-unused %s

struct A {
int y;
};

struct B; // expected-note 4{{forward declaration of 'B'}}

void f(A *a, B *b) {
a->B::x; // expected-error {{incomplete type 'B' named in nested name specifier}}
a->A::x; // expected-error {{no member named 'x' in 'A'}}
a->A::y;
b->B::x; // expected-error {{member access into incomplete type 'B'}}
b->A::x; // expected-error {{member access into incomplete type 'B'}}
b->A::y; // expected-error {{member access into incomplete type 'B'}}
}
31 changes: 31 additions & 0 deletions clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -574,3 +574,34 @@ namespace N4 {
}
};
} // namespace N4

namespace N5 {
struct A {
int x;
};

template<typename T>
void f() {
A y = T::x; // expected-error {{type 'int' cannot be used prior to '::' because it has no members}}
y.x;
}

template void f<int>(); // expected-note {{in instantiation of}}

struct B {
template<typename T>
B(T&&);

int x;
};

template<typename T>
void g(T y) {
B z([&]() { // expected-note {{while substituting into a lambda expression here}}
h(&y); // expected-error {{use of undeclared identifier 'h'}}
});
z.x;
}

template void g(int); // expected-note {{in instantiation of}}
} // namespace N5
26 changes: 13 additions & 13 deletions clang/test/CodeGen/aarch64-branch-protection-attr.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,29 +67,29 @@ __attribute__ ((target("branch-protection=gcs")))
void gcs() {}
// CHECK: define{{.*}} void @gcs() #[[#GCS:]]

// CHECK-DAG: attributes #[[#NONE]] = { {{.*}} "branch-target-enforcement"="false" "guarded-control-stack"="false" {{.*}} "sign-return-address"="none"
// CHECK-DAG: attributes #[[#NONE]] = { {{.*}}

// CHECK-DAG: attributes #[[#STD]] = { {{.*}} "branch-target-enforcement"="true" "guarded-control-stack"="true" {{.*}} "sign-return-address"="non-leaf" "sign-return-address-key"="a_key"
// CHECK-DAG: attributes #[[#STD]] = { {{.*}} "branch-target-enforcement" "guarded-control-stack" {{.*}} "sign-return-address"="non-leaf" "sign-return-address-key"="a_key"

// CHECK-DAG: attributes #[[#BTI]] = { {{.*}} "branch-target-enforcement"="true" "guarded-control-stack"="false" {{.*}} "sign-return-address"="none"
// CHECK-DAG: attributes #[[#BTI]] = { {{.*}} "branch-target-enforcement"

// CHECK-DAG: attributes #[[#PAC]] = { {{.*}} "branch-target-enforcement"="false" "guarded-control-stack"="false" {{.*}} "sign-return-address"="non-leaf" "sign-return-address-key"="a_key"
// CHECK-DAG: attributes #[[#PAC]] = { {{.*}} "sign-return-address"="non-leaf" "sign-return-address-key"="a_key"

// CHECK-DAG: attributes #[[#PACLEAF]] = { {{.*}} "branch-target-enforcement"="false" "guarded-control-stack"="false" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"
// CHECK-DAG: attributes #[[#PACLEAF]] = { {{.*}} "sign-return-address"="all" "sign-return-address-key"="a_key"

// CHECK-DAG: attributes #[[#PACBKEY]] = { {{.*}}"branch-target-enforcement"="false" "guarded-control-stack"="false" {{.*}} "sign-return-address"="non-leaf" "sign-return-address-key"="b_key"
// CHECK-DAG: attributes #[[#PACBKEY]] = { {{.*}} "sign-return-address"="non-leaf" "sign-return-address-key"="b_key"

// CHECK-DAG: attributes #[[#PACBKEYLEAF]] = { {{.*}} "branch-target-enforcement"="false" "guarded-control-stack"="false" {{.*}}"sign-return-address"="all" "sign-return-address-key"="b_key"
// CHECK-DAG: attributes #[[#PACBKEYLEAF]] = { {{.*}} "sign-return-address"="all" "sign-return-address-key"="b_key"

// CHECK-DAG: attributes #[[#BTIPACLEAF]] = { {{.*}}"branch-target-enforcement"="true" "guarded-control-stack"="false" {{.*}} "sign-return-address"="all" "sign-return-address-key"="a_key"
// CHECK-DAG: attributes #[[#BTIPACLEAF]] = { {{.*}} "branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"


// CHECK-DAG: attributes #[[#PAUTHLR]] = { {{.*}}"branch-protection-pauth-lr"="true" {{.*}}"branch-target-enforcement"="false" "guarded-control-stack"="false" {{.*}}"sign-return-address"="non-leaf" "sign-return-address-key"="a_key"
// CHECK-DAG: attributes #[[#PAUTHLR]] = { {{.*}} "branch-protection-pauth-lr" {{.*}}"sign-return-address"="non-leaf" "sign-return-address-key"="a_key"

// CHECK-DAG: attributes #[[#PAUTHLR_BKEY]] = { {{.*}}"branch-protection-pauth-lr"="true" {{.*}}"branch-target-enforcement"="false" "guarded-control-stack"="false" {{.*}}"sign-return-address"="non-leaf" "sign-return-address-key"="b_key"
// CHECK-DAG: attributes #[[#PAUTHLR_BKEY]] = { {{.*}} "branch-protection-pauth-lr" {{.*}}"sign-return-address"="non-leaf" "sign-return-address-key"="b_key"

// CHECK-DAG: attributes #[[#PAUTHLR_LEAF]] = { {{.*}}"branch-protection-pauth-lr"="true" {{.*}}"branch-target-enforcement"="false" "guarded-control-stack"="false" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"
// CHECK-DAG: attributes #[[#PAUTHLR_LEAF]] = { {{.*}} "branch-protection-pauth-lr" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"

// CHECK-DAG: attributes #[[#PAUTHLR_BTI]] = { {{.*}}"branch-protection-pauth-lr"="true" {{.*}}"branch-target-enforcement"="true" "guarded-control-stack"="false" {{.*}}"sign-return-address"="non-leaf" "sign-return-address-key"="a_key"
// CHECK-DAG: attributes #[[#PAUTHLR_BTI]] = { {{.*}} "branch-protection-pauth-lr" {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="non-leaf" "sign-return-address-key"="a_key"

// CHECK-DAG: attributes #[[#GCS]] = { {{.*}}"branch-target-enforcement"="false" "guarded-control-stack"="true" {{.*}} "sign-return-address"="none"
// CHECK-DAG: attributes #[[#GCS]] = { {{.*}} "guarded-control-stack"
23 changes: 23 additions & 0 deletions clang/test/CodeGen/aarch64-inlineasm-ios.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// REQUIRES: aarch64-registered-target
// RUN: %clang_cc1 -triple arm64-apple-ios -S -o - %s | FileCheck %s

// CHECK: _restartable_function:
// CHECK-NEXT: ldr x11, [x0]
// CHECK-NEXT: add x11, x11, #1
// CHECK-NEXT: str x11, [x0]
// CHECK-NEXT: Ltmp0:
// CHECK-NEXT: b Ltmp0
// CHECK-NEXT: LExit_restartable_function:
// CHECK-NEXT: ret
asm(".align 4\n"
" .text\n"
" .private_extern _restartable_function\n"
"_restartable_function:\n"
" ldr x11, [x0]\n"
" add x11, x11, #1\n"
" str x11, [x0]\n"
"1:\n"
" b 1b\n"
"LExit_restartable_function:\n"
" ret\n"
);
12 changes: 9 additions & 3 deletions clang/test/CodeGen/aarch64-sign-return-address.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,15 @@

// CHECK-LABEL: @foo() #[[#ATTR:]]

// CHECK-NOT: attributes #[[#ATTR]] = { {{.*}} "sign-return-address"
// CHECK-NOT: attributes #[[#ATTR]] = { {{.*}} "sign-return-address-key"
// CHECK-NOT: attributes #[[#ATTR]] = { {{.*}} "branch-target-enforcement"
// NONE-NOT: attributes #[[#ATTR]] = { {{.*}} "sign-return-address"
// NONE-NOT: attributes #[[#ATTR]] = { {{.*}} "sign-return-address-key"
// NONE-NOT: attributes #[[#ATTR]] = { {{.*}} "branch-target-enforcement"

// ALL: attributes #[[#ATTR]] = { {{.*}} "sign-return-address"
// PART: attributes #[[#ATTR]] = { {{.*}} "sign-return-address-key"="a_key"
// B-KEY: attributes #[[#ATTR]] = { {{.*}} "sign-return-address-key"="b_key"
// BTE: attributes #[[#ATTR]] = { {{.*}} "branch-target-enforcement"


// Check module attributes

Expand Down
2 changes: 1 addition & 1 deletion clang/test/CodeGen/aarch64-targetattr.c
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ void minusarch() {}
// CHECK: attributes #[[ATTR12]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+fullfp16,+sve" }
// CHECK: attributes #[[ATTR13]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+fullfp16" }
// CHECK: attributes #[[ATTR14]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="neoverse-n1" "target-features"="+aes,+bf16,+complxnum,+crc,+dotprod,+fp-armv8,+fullfp16,+i8mm,+jsconv,+lse,+neon,+pauth,+perfmon,+ras,+rcpc,+rdm,+sha2,+spe,+ssbs,+sve,+sve2,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8.6a,+v8a" "tune-cpu"="cortex-a710" }
// CHECK: attributes #[[ATTR15]] = { noinline nounwind optnone "branch-protection-pauth-lr"="false" "branch-target-enforcement"="true" "guarded-control-stack"="true" "no-trapping-math"="true" "sign-return-address"="non-leaf" "sign-return-address-key"="a_key" "stack-protector-buffer-size"="8" "target-cpu"="neoverse-n1" "target-features"="+aes,+bf16,+complxnum,+crc,+dotprod,+fp-armv8,+fullfp16,+i8mm,+jsconv,+lse,+neon,+pauth,+perfmon,+ras,+rcpc,+rdm,+sha2,+spe,+ssbs,+sve,+sve2,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8.6a,+v8a" "tune-cpu"="cortex-a710" }
// CHECK: attributes #[[ATTR15]] = { noinline nounwind optnone "branch-target-enforcement" "guarded-control-stack" "no-trapping-math"="true" "sign-return-address"="non-leaf" "sign-return-address-key"="a_key" "stack-protector-buffer-size"="8" "target-cpu"="neoverse-n1" "target-features"="+aes,+bf16,+complxnum,+crc,+dotprod,+fp-armv8,+fullfp16,+i8mm,+jsconv,+lse,+neon,+pauth,+perfmon,+ras,+rcpc,+rdm,+sha2,+spe,+ssbs,+sve,+sve2,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8.6a,+v8a" "tune-cpu"="cortex-a710" }
// CHECK: attributes #[[ATTR16]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
// CHECK: attributes #[[ATTR17]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="-v9.3a" }
//.
Expand Down
12 changes: 6 additions & 6 deletions clang/test/CodeGen/arm-branch-protection-attr-1.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ __attribute__((target("branch-protection=pac-ret+leaf"))) void leaf() {}
__attribute__((target("branch-protection=pac-ret+leaf+bti"))) void btileaf() {}
// CHECK: define{{.*}} void @btileaf() #[[#BTIPACLEAF:]]

// CHECK-DAG: attributes #[[#NONE]] = { {{.*}} "branch-target-enforcement"="false" {{.*}} "sign-return-address"="none"
// CHECK-DAG: attributes #[[#NONE]] = { {{.*}}

// CHECK-DAG: attributes #[[#STD]] = { {{.*}} "branch-target-enforcement"="true" {{.*}} "sign-return-address"="non-leaf"
// CHECK-DAG: attributes #[[#STD]] = { {{.*}} "branch-target-enforcement" {{.*}} "sign-return-address"="non-leaf"

// CHECK-DAG: attributes #[[#BTI]] = { {{.*}} "branch-target-enforcement"="true" {{.*}} "sign-return-address"="none"
// CHECK-DAG: attributes #[[#BTI]] = { {{.*}} "branch-target-enforcement"

// CHECK-DAG: attributes #[[#PAC]] = { {{.*}} "branch-target-enforcement"="false" {{.*}} "sign-return-address"="non-leaf"
// CHECK-DAG: attributes #[[#PAC]] = { {{.*}} "sign-return-address"="non-leaf"

// CHECK-DAG: attributes #[[#PACLEAF]] = { {{.*}} "branch-target-enforcement"="false" {{.*}}"sign-return-address"="all"
// CHECK-DAG: attributes #[[#PACLEAF]] = { {{.*}} "sign-return-address"="all"

// CHECK-DAG: attributes #[[#BTIPACLEAF]] = { {{.*}}"branch-target-enforcement"="true" {{.*}} "sign-return-address"="all"
// CHECK-DAG: attributes #[[#BTIPACLEAF]] = { {{.*}} "branch-target-enforcement" {{.*}} "sign-return-address"="all"
13 changes: 9 additions & 4 deletions clang/test/CodeGen/arm-branch-protection-attr-2.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,18 @@
// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main -S -emit-llvm -o - -mbranch-protection=pac-ret+b-key %s | FileCheck %s --check-prefix=CHECK --check-prefix=PART
// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main -S -emit-llvm -o - -mbranch-protection=bti %s | FileCheck %s --check-prefix=CHECK --check-prefix=BTE

// Check there are no branch protection function attributes
// Check there are branch protection function attributes

// CHECK-LABEL: @foo() #[[#ATTR:]]

// CHECK-NOT: attributes #[[#ATTR]] = { {{.*}} "sign-return-address"
// CHECK-NOT: attributes #[[#ATTR]] = { {{.*}} "sign-return-address-key"
// CHECK-NOT: attributes #[[#ATTR]] = { {{.*}} "branch-target-enforcement"
// NONE-NOT: attributes #[[#ATTR]] = { {{.*}} "sign-return-address"
// NONE-NOT: attributes #[[#ATTR]] = { {{.*}} "sign-return-address-key"
// NONE-NOT: attributes #[[#ATTR]] = { {{.*}} "branch-target-enforcement"

// ALL: attributes #[[#ATTR]] = { {{.*}} "sign-return-address"="all"
// PART: attributes #[[#ATTR]] = { {{.*}} "sign-return-address"="non-leaf"
// BTE: attributes #[[#ATTR]] = { {{.*}} "branch-target-enforcement"


// Check module attributes

Expand Down
13 changes: 10 additions & 3 deletions clang/test/CodeGen/blocks.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -Wno-strict-prototypes -o - -fblocks | FileCheck %s
// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -Wno-strict-prototypes -o - -fblocks | FileCheck --check-prefix=CHECK --check-prefix=SIG_STR %s
// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -Wno-strict-prototypes -o - -fblocks -fdisable-block-signature-string | FileCheck --check-prefix=CHECK --check-prefix=NO_SIG_STR %s

// CHECK: @{{.*}} = internal constant { i32, i32, ptr, ptr, ptr, ptr } { i32 0, i32 24, ptr @__copy_helper_block_4_20r, ptr @__destroy_helper_block_4_20r, ptr @{{.*}}, ptr null }, align 4
// CHECK: @[[BLOCK_DESCRIPTOR_TMP21:.*]] = internal constant { i32, i32, ptr, ptr, ptr, ptr } { i32 0, i32 24, ptr @__copy_helper_block_4_20r, ptr @__destroy_helper_block_4_20r, ptr @{{.*}}, ptr null }, align 4
// SIG_STR: @[[STR:.*]] = private unnamed_addr constant [6 x i8] c"v4@?0\00", align 1
// SIG_STR: @{{.*}} = internal constant { ptr, i32, i32, ptr, ptr } { ptr @_NSConcreteGlobalBlock, i32 1342177280, i32 0, ptr @f_block_invoke, ptr @{{.*}} }, align 4
// NO_SIG_STR: @{{.*}} = internal constant { ptr, i32, i32, ptr, ptr } { ptr @_NSConcreteGlobalBlock, i32 268435456, i32 0, ptr @f_block_invoke, ptr @{{.*}} }, align 4

// SIG_STR: @{{.*}} = internal constant { i32, i32, ptr, ptr, ptr, ptr } { i32 0, i32 24, ptr @__copy_helper_block_4_20r, ptr @__destroy_helper_block_4_20r, ptr @[[STR]], ptr null }, align 4
// SIG_STR: @[[BLOCK_DESCRIPTOR_TMP21:.*]] = internal constant { i32, i32, ptr, ptr, ptr, ptr } { i32 0, i32 24, ptr @__copy_helper_block_4_20r, ptr @__destroy_helper_block_4_20r, ptr @[[STR]], ptr null }, align 4
// NO_SIG_STR: @{{.*}} = internal constant { i32, i32, ptr, ptr, ptr, ptr } { i32 0, i32 24, ptr @__copy_helper_block_4_20r, ptr @__destroy_helper_block_4_20r, ptr null, ptr null }, align 4
// NO_SIG_STR: @[[BLOCK_DESCRIPTOR_TMP21:.*]] = internal constant { i32, i32, ptr, ptr, ptr, ptr } { i32 0, i32 24, ptr @__copy_helper_block_4_20r, ptr @__destroy_helper_block_4_20r, ptr null, ptr null }, align 4

void (^f)(void) = ^{};

Expand Down
Loading