17 changes: 10 additions & 7 deletions clang/lib/Driver/ToolChains/Flang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,10 +170,9 @@ void Flang::AddAArch64TargetArgs(const ArgList &Args,
if (Arg *A = Args.getLastArg(options::OPT_msve_vector_bits_EQ)) {
StringRef Val = A->getValue();
const Driver &D = getToolChain().getDriver();
if (Val.equals("128") || Val.equals("256") || Val.equals("512") ||
Val.equals("1024") || Val.equals("2048") || Val.equals("128+") ||
Val.equals("256+") || Val.equals("512+") || Val.equals("1024+") ||
Val.equals("2048+")) {
if (Val == "128" || Val == "256" || Val == "512" || Val == "1024" ||
Val == "2048" || Val == "128+" || Val == "256+" || Val == "512+" ||
Val == "1024+" || Val == "2048+") {
unsigned Bits = 0;
if (!Val.consume_back("+")) {
[[maybe_unused]] bool Invalid = Val.getAsInteger(10, Bits);
Expand All @@ -187,7 +186,7 @@ void Flang::AddAArch64TargetArgs(const ArgList &Args,
CmdArgs.push_back(
Args.MakeArgString("-mvscale-min=" + llvm::Twine(Bits / 128)));
// Silently drop requests for vector-length agnostic code as it's implied.
} else if (!Val.equals("scalable"))
} else if (Val != "scalable")
// Handle the unsupported values passed to msve-vector-bits.
D.Diag(diag::err_drv_unsupported_option_argument)
<< A->getSpelling() << Val;
Expand All @@ -214,7 +213,7 @@ void Flang::AddRISCVTargetArgs(const ArgList &Args,
// If the value is "zvl", use MinVLen from march. Otherwise, try to parse
// as integer as long as we have a MinVLen.
unsigned Bits = 0;
if (Val.equals("zvl") && MinVLen >= llvm::RISCV::RVVBitsPerBlock) {
if (Val == "zvl" && MinVLen >= llvm::RISCV::RVVBitsPerBlock) {
Bits = MinVLen;
} else if (!Val.getAsInteger(10, Bits)) {
// Only accept power of 2 values beteen RVVBitsPerBlock and 65536 that
Expand All @@ -231,7 +230,7 @@ void Flang::AddRISCVTargetArgs(const ArgList &Args,
Args.MakeArgString("-mvscale-max=" + llvm::Twine(VScaleMin)));
CmdArgs.push_back(
Args.MakeArgString("-mvscale-min=" + llvm::Twine(VScaleMin)));
} else if (!Val.equals("scalable")) {
} else if (Val != "scalable") {
// Handle the unsupported values passed to mrvv-vector-bits.
D.Diag(diag::err_drv_unsupported_option_argument)
<< A->getSpelling() << Val;
Expand Down Expand Up @@ -748,6 +747,10 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA,
// Add other compile options
addOtherOptions(Args, CmdArgs);

// Disable all warnings
// TODO: Handle interactions between -w, -pedantic, -Wall, -WOption
Args.AddLastArg(CmdArgs, options::OPT_w);

// Forward flags for OpenMP. We don't do this if the current action is an
// device offloading action other than OpenMP.
if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
Expand Down
29 changes: 0 additions & 29 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
44 changes: 42 additions & 2 deletions clang/lib/Driver/ToolChains/HLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,49 @@ std::optional<std::string> tryParseProfile(StringRef Profile) {
else if (llvm::getAsUnsignedInteger(Parts[2], 0, Minor))
return std::nullopt;

// dxil-unknown-shadermodel-hull
// Determine DXIL version using the minor version number of Shader
// Model version specified in target profile. Prior to decoupling DXIL version
// numbering from that of Shader Model DXIL version 1.Y corresponds to SM 6.Y.
// E.g., dxilv1.Y-unknown-shadermodelX.Y-hull
llvm::Triple T;
T.setArch(Triple::ArchType::dxil);
Triple::SubArchType SubArch = llvm::Triple::NoSubArch;
switch (Minor) {
case 0:
SubArch = llvm::Triple::DXILSubArch_v1_0;
break;
case 1:
SubArch = llvm::Triple::DXILSubArch_v1_1;
break;
case 2:
SubArch = llvm::Triple::DXILSubArch_v1_2;
break;
case 3:
SubArch = llvm::Triple::DXILSubArch_v1_3;
break;
case 4:
SubArch = llvm::Triple::DXILSubArch_v1_4;
break;
case 5:
SubArch = llvm::Triple::DXILSubArch_v1_5;
break;
case 6:
SubArch = llvm::Triple::DXILSubArch_v1_6;
break;
case 7:
SubArch = llvm::Triple::DXILSubArch_v1_7;
break;
case 8:
SubArch = llvm::Triple::DXILSubArch_v1_8;
break;
case OfflineLibMinor:
// Always consider minor version x as the latest supported DXIL version
SubArch = llvm::Triple::LatestDXILSubArch;
break;
default:
// No DXIL Version corresponding to specified Shader Model version found
return std::nullopt;
}
T.setArch(Triple::ArchType::dxil, SubArch);
T.setOSName(Triple::getOSTypeName(Triple::OSType::ShaderModel).str() +
VersionTuple(Major, Minor).getAsString());
T.setEnvironment(Kind);
Expand Down
3 changes: 1 addition & 2 deletions clang/lib/Format/Format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3858,8 +3858,7 @@ LangOptions getFormattingLangOpts(const FormatStyle &Style) {
LangOpts.Digraphs = LexingStd >= FormatStyle::LS_Cpp11;

LangOpts.LineComment = 1;
bool AlternativeOperators = Style.isCpp();
LangOpts.CXXOperatorNames = AlternativeOperators ? 1 : 0;
LangOpts.CXXOperatorNames = Style.isCpp();
LangOpts.Bool = 1;
LangOpts.ObjC = 1;
LangOpts.MicrosoftExt = 1; // To get kw___try, kw___finally.
Expand Down
46 changes: 5 additions & 41 deletions clang/lib/Format/FormatToken.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,59 +34,23 @@ const char *getTokenTypeName(TokenType Type) {
return nullptr;
}

// FIXME: This is copy&pasted from Sema. Put it in a common place and remove
// duplication.
bool FormatToken::isSimpleTypeSpecifier() const {
switch (Tok.getKind()) {
case tok::kw_short:
case tok::kw_long:
case tok::kw___int64:
case tok::kw___int128:
case tok::kw_signed:
case tok::kw_unsigned:
case tok::kw_void:
case tok::kw_char:
case tok::kw_int:
case tok::kw_half:
case tok::kw_float:
case tok::kw_double:
case tok::kw___bf16:
case tok::kw__Float16:
case tok::kw___float128:
case tok::kw___ibm128:
case tok::kw_wchar_t:
case tok::kw_bool:
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
#include "clang/Basic/TransformTypeTraits.def"
case tok::annot_typename:
case tok::kw_char8_t:
case tok::kw_char16_t:
case tok::kw_char32_t:
case tok::kw_typeof:
case tok::kw_decltype:
case tok::kw__Atomic:
return true;
default:
return false;
}
}

// Sorted common C++ non-keyword types.
static SmallVector<StringRef> CppNonKeywordTypes = {
"clock_t", "int16_t", "int32_t", "int64_t", "int8_t",
"intptr_t", "ptrdiff_t", "size_t", "time_t", "uint16_t",
"uint32_t", "uint64_t", "uint8_t", "uintptr_t",
};

bool FormatToken::isTypeName(bool IsCpp) const {
return is(TT_TypeName) || isSimpleTypeSpecifier() ||
bool FormatToken::isTypeName(const LangOptions &LangOpts) const {
const bool IsCpp = LangOpts.CXXOperatorNames;
return is(TT_TypeName) || Tok.isSimpleTypeSpecifier(LangOpts) ||
(IsCpp && is(tok::identifier) &&
std::binary_search(CppNonKeywordTypes.begin(),
CppNonKeywordTypes.end(), TokenText));
}

bool FormatToken::isTypeOrIdentifier(bool IsCpp) const {
return isTypeName(IsCpp) || isOneOf(tok::kw_auto, tok::identifier);
bool FormatToken::isTypeOrIdentifier(const LangOptions &LangOpts) const {
return isTypeName(LangOpts) || isOneOf(tok::kw_auto, tok::identifier);
}

bool FormatToken::isBlockIndentedInitRBrace(const FormatStyle &Style) const {
Expand Down
8 changes: 2 additions & 6 deletions clang/lib/Format/FormatToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -684,12 +684,8 @@ struct FormatToken {
isAttribute();
}

/// Determine whether the token is a simple-type-specifier.
[[nodiscard]] bool isSimpleTypeSpecifier() const;

[[nodiscard]] bool isTypeName(bool IsCpp) const;

[[nodiscard]] bool isTypeOrIdentifier(bool IsCpp) const;
[[nodiscard]] bool isTypeName(const LangOptions &LangOpts) const;
[[nodiscard]] bool isTypeOrIdentifier(const LangOptions &LangOpts) const;

bool isObjCAccessSpecifier() const {
return is(tok::at) && Next &&
Expand Down
1 change: 0 additions & 1 deletion clang/lib/Format/FormatTokenLexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1442,7 +1442,6 @@ void FormatTokenLexer::readRawToken(FormatToken &Tok) {

void FormatTokenLexer::resetLexer(unsigned Offset) {
StringRef Buffer = SourceMgr.getBufferData(ID);
LangOpts = getFormattingLangOpts(Style);
Lex.reset(new Lexer(SourceMgr.getLocForStartOfFile(ID), LangOpts,
Buffer.begin(), Buffer.begin() + Offset, Buffer.end()));
Lex->SetKeepWhitespaceMode(true);
Expand Down
24 changes: 11 additions & 13 deletions clang/lib/Format/QualifierAlignmentFixer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,13 +268,11 @@ const FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight(
if (isPossibleMacro(TypeToken))
return Tok;

const bool IsCpp = Style.isCpp();

// The case `const long long int volatile` -> `long long int const volatile`
// The case `long const long int volatile` -> `long long int const volatile`
// The case `long long volatile int const` -> `long long int const volatile`
// The case `const long long volatile int` -> `long long int const volatile`
if (TypeToken->isTypeName(IsCpp)) {
if (TypeToken->isTypeName(LangOpts)) {
// The case `const decltype(foo)` -> `const decltype(foo)`
// The case `const typeof(foo)` -> `const typeof(foo)`
// The case `const _Atomic(foo)` -> `const _Atomic(foo)`
Expand All @@ -283,7 +281,7 @@ const FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight(

const FormatToken *LastSimpleTypeSpecifier = TypeToken;
while (isQualifierOrType(LastSimpleTypeSpecifier->getNextNonComment(),
IsCpp)) {
LangOpts)) {
LastSimpleTypeSpecifier = LastSimpleTypeSpecifier->getNextNonComment();
}

Expand All @@ -295,7 +293,7 @@ const FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight(
// The case `unsigned short const` -> `unsigned short const`
// The case:
// `unsigned short volatile const` -> `unsigned short const volatile`
if (PreviousCheck && PreviousCheck->isTypeName(IsCpp)) {
if (PreviousCheck && PreviousCheck->isTypeName(LangOpts)) {
if (LastQual != Tok)
rotateTokens(SourceMgr, Fixes, Tok, LastQual, /*Left=*/false);
return Tok;
Expand Down Expand Up @@ -412,11 +410,11 @@ const FormatToken *LeftRightQualifierAlignmentFixer::analyzeLeft(
// The case `volatile long long const int` -> `const volatile long long int`
// The case `const long long volatile int` -> `const volatile long long int`
// The case `long volatile long int const` -> `const volatile long long int`
if (const bool IsCpp = Style.isCpp(); TypeToken->isTypeName(IsCpp)) {
if (TypeToken->isTypeName(LangOpts)) {
const FormatToken *LastSimpleTypeSpecifier = TypeToken;
while (isConfiguredQualifierOrType(
LastSimpleTypeSpecifier->getPreviousNonComment(),
ConfiguredQualifierTokens, IsCpp)) {
ConfiguredQualifierTokens, LangOpts)) {
LastSimpleTypeSpecifier =
LastSimpleTypeSpecifier->getPreviousNonComment();
}
Expand Down Expand Up @@ -614,16 +612,16 @@ void prepareLeftRightOrderingForQualifierAlignmentFixer(
}
}

bool LeftRightQualifierAlignmentFixer::isQualifierOrType(const FormatToken *Tok,
bool IsCpp) {
return Tok &&
(Tok->isTypeName(IsCpp) || Tok->is(tok::kw_auto) || isQualifier(Tok));
bool LeftRightQualifierAlignmentFixer::isQualifierOrType(
const FormatToken *Tok, const LangOptions &LangOpts) {
return Tok && (Tok->isTypeName(LangOpts) || Tok->is(tok::kw_auto) ||
isQualifier(Tok));
}

bool LeftRightQualifierAlignmentFixer::isConfiguredQualifierOrType(
const FormatToken *Tok, const std::vector<tok::TokenKind> &Qualifiers,
bool IsCpp) {
return Tok && (Tok->isTypeName(IsCpp) || Tok->is(tok::kw_auto) ||
const LangOptions &LangOpts) {
return Tok && (Tok->isTypeName(LangOpts) || Tok->is(tok::kw_auto) ||
isConfiguredQualifier(Tok, Qualifiers));
}

Expand Down
5 changes: 3 additions & 2 deletions clang/lib/Format/QualifierAlignmentFixer.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,12 @@ class LeftRightQualifierAlignmentFixer : public TokenAnalyzer {
tok::TokenKind QualifierType);

// Is the Token a simple or qualifier type
static bool isQualifierOrType(const FormatToken *Tok, bool IsCpp = true);
static bool isQualifierOrType(const FormatToken *Tok,
const LangOptions &LangOpts);
static bool
isConfiguredQualifierOrType(const FormatToken *Tok,
const std::vector<tok::TokenKind> &Qualifiers,
bool IsCpp = true);
const LangOptions &LangOpts);

// Is the Token likely a Macro
static bool isPossibleMacro(const FormatToken *Tok);
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Format/TokenAnalyzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ Environment::Environment(StringRef Code, StringRef FileName,
NextStartColumn(NextStartColumn), LastStartColumn(LastStartColumn) {}

TokenAnalyzer::TokenAnalyzer(const Environment &Env, const FormatStyle &Style)
: Style(Style), Env(Env),
: Style(Style), LangOpts(getFormattingLangOpts(Style)), Env(Env),
AffectedRangeMgr(Env.getSourceManager(), Env.getCharRanges()),
UnwrappedLines(1),
Encoding(encoding::detectEncoding(
Expand All @@ -101,7 +101,7 @@ std::pair<tooling::Replacements, unsigned>
TokenAnalyzer::process(bool SkipAnnotation) {
tooling::Replacements Result;
llvm::SpecificBumpPtrAllocator<FormatToken> Allocator;
IdentifierTable IdentTable(getFormattingLangOpts(Style));
IdentifierTable IdentTable(LangOpts);
FormatTokenLexer Lex(Env.getSourceManager(), Env.getFileID(),
Env.getFirstStartColumn(), Style, Encoding, Allocator,
IdentTable);
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Format/TokenAnalyzer.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ class TokenAnalyzer : public UnwrappedLineConsumer {
void finishRun() override;

FormatStyle Style;
LangOptions LangOpts;
// Stores Style, FileID and SourceManager etc.
const Environment &Env;
// AffectedRangeMgr stores ranges to be fixed.
Expand Down
43 changes: 25 additions & 18 deletions clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,9 @@ class AnnotatingParser {
const AdditionalKeywords &Keywords,
SmallVector<ScopeType> &Scopes)
: Style(Style), Line(Line), CurrentToken(Line.First), AutoFound(false),
IsCpp(Style.isCpp()), Keywords(Keywords), Scopes(Scopes) {
IsCpp(Style.isCpp()), LangOpts(getFormattingLangOpts(Style)),
Keywords(Keywords), Scopes(Scopes) {
assert(IsCpp == LangOpts.CXXOperatorNames);
Contexts.push_back(Context(tok::unknown, 1, /*IsExpression=*/false));
resetTokenMetadata();
}
Expand Down Expand Up @@ -562,7 +564,7 @@ class AnnotatingParser {
(CurrentToken->is(tok::l_paren) && CurrentToken->Next &&
CurrentToken->Next->isOneOf(tok::star, tok::amp, tok::caret));
if ((CurrentToken->Previous->isOneOf(tok::kw_const, tok::kw_auto) ||
CurrentToken->Previous->isTypeName(IsCpp)) &&
CurrentToken->Previous->isTypeName(LangOpts)) &&
!(CurrentToken->is(tok::l_brace) ||
(CurrentToken->is(tok::l_paren) && !ProbablyFunctionTypeLParen))) {
Contexts.back().IsExpression = false;
Expand Down Expand Up @@ -2624,7 +2626,7 @@ class AnnotatingParser {
return true;

// MyClass a;
if (PreviousNotConst->isTypeName(IsCpp))
if (PreviousNotConst->isTypeName(LangOpts))
return true;

// type[] a in Java
Expand Down Expand Up @@ -2728,7 +2730,7 @@ class AnnotatingParser {
}

if (Tok.Next->is(tok::question) ||
(Tok.Next->is(tok::ampamp) && !Tok.Previous->isTypeName(IsCpp))) {
(Tok.Next->is(tok::ampamp) && !Tok.Previous->isTypeName(LangOpts))) {
return false;
}

Expand Down Expand Up @@ -2757,9 +2759,10 @@ class AnnotatingParser {
}

// Heuristically try to determine whether the parentheses contain a type.
auto IsQualifiedPointerOrReference = [](FormatToken *T, bool IsCpp) {
auto IsQualifiedPointerOrReference = [](FormatToken *T,
const LangOptions &LangOpts) {
// This is used to handle cases such as x = (foo *const)&y;
assert(!T->isTypeName(IsCpp) && "Should have already been checked");
assert(!T->isTypeName(LangOpts) && "Should have already been checked");
// Strip trailing qualifiers such as const or volatile when checking
// whether the parens could be a cast to a pointer/reference type.
while (T) {
Expand Down Expand Up @@ -2791,8 +2794,8 @@ class AnnotatingParser {
bool ParensAreType =
!Tok.Previous ||
Tok.Previous->isOneOf(TT_TemplateCloser, TT_TypeDeclarationParen) ||
Tok.Previous->isTypeName(IsCpp) ||
IsQualifiedPointerOrReference(Tok.Previous, IsCpp);
Tok.Previous->isTypeName(LangOpts) ||
IsQualifiedPointerOrReference(Tok.Previous, LangOpts);
bool ParensCouldEndDecl =
Tok.Next->isOneOf(tok::equal, tok::semi, tok::l_brace, tok::greater);
if (ParensAreType && !ParensCouldEndDecl)
Expand Down Expand Up @@ -3065,6 +3068,7 @@ class AnnotatingParser {
FormatToken *CurrentToken;
bool AutoFound;
bool IsCpp;
LangOptions LangOpts;
const AdditionalKeywords &Keywords;

SmallVector<ScopeType> &Scopes;
Expand Down Expand Up @@ -3639,7 +3643,8 @@ void TokenAnnotator::annotate(AnnotatedLine &Line) {

// This function heuristically determines whether 'Current' starts the name of a
// function declaration.
static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current,
static bool isFunctionDeclarationName(const LangOptions &LangOpts,
const FormatToken &Current,
const AnnotatedLine &Line,
FormatToken *&ClosingParen) {
assert(Current.Previous);
Expand All @@ -3658,7 +3663,7 @@ static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current,
}

auto skipOperatorName =
[IsCpp](const FormatToken *Next) -> const FormatToken * {
[&LangOpts](const FormatToken *Next) -> const FormatToken * {
for (; Next; Next = Next->Next) {
if (Next->is(TT_OverloadedOperatorLParen))
return Next;
Expand All @@ -3677,7 +3682,7 @@ static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current,
Next = Next->Next;
continue;
}
if ((Next->isTypeName(IsCpp) || Next->is(tok::identifier)) &&
if ((Next->isTypeName(LangOpts) || Next->is(tok::identifier)) &&
Next->Next && Next->Next->isPointerOrReference()) {
// For operator void*(), operator char*(), operator Foo*().
Next = Next->Next;
Expand All @@ -3693,8 +3698,10 @@ static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current,
return nullptr;
};

const auto *Next = Current.Next;
const bool IsCpp = LangOpts.CXXOperatorNames;

// Find parentheses of parameter list.
const FormatToken *Next = Current.Next;
if (Current.is(tok::kw_operator)) {
if (Previous.Tok.getIdentifierInfo() &&
!Previous.isOneOf(tok::kw_return, tok::kw_co_return)) {
Expand Down Expand Up @@ -3774,7 +3781,7 @@ static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current,
Tok = Tok->MatchingParen;
continue;
}
if (Tok->is(tok::kw_const) || Tok->isTypeName(IsCpp) ||
if (Tok->is(tok::kw_const) || Tok->isTypeName(LangOpts) ||
Tok->isOneOf(TT_PointerOrReference, TT_StartOfName, tok::ellipsis)) {
return true;
}
Expand Down Expand Up @@ -3837,7 +3844,7 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) const {
AfterLastAttribute = Tok;
if (const bool IsCtorOrDtor = Tok->is(TT_CtorDtorDeclName);
IsCtorOrDtor ||
isFunctionDeclarationName(IsCpp, *Tok, Line, ClosingParen)) {
isFunctionDeclarationName(LangOpts, *Tok, Line, ClosingParen)) {
if (!IsCtorOrDtor)
Tok->setFinalizedType(TT_FunctionDeclarationName);
LineIsFunctionDeclaration = true;
Expand Down Expand Up @@ -4447,7 +4454,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
if (Left.Tok.isLiteral())
return true;
// for (auto a = 0, b = 0; const auto & c : {1, 2, 3})
if (Left.isTypeOrIdentifier(IsCpp) && Right.Next && Right.Next->Next &&
if (Left.isTypeOrIdentifier(LangOpts) && Right.Next && Right.Next->Next &&
Right.Next->Next->is(TT_RangeBasedForLoopColon)) {
return getTokenPointerOrReferenceAlignment(Right) !=
FormatStyle::PAS_Left;
Expand Down Expand Up @@ -4490,7 +4497,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
if (Right.is(tok::l_brace) && Right.is(BK_Block))
return true;
// for (auto a = 0, b = 0; const auto& c : {1, 2, 3})
if (BeforeLeft && BeforeLeft->isTypeOrIdentifier(IsCpp) && Right.Next &&
if (BeforeLeft && BeforeLeft->isTypeOrIdentifier(LangOpts) && Right.Next &&
Right.Next->is(TT_RangeBasedForLoopColon)) {
return getTokenPointerOrReferenceAlignment(Left) !=
FormatStyle::PAS_Right;
Expand Down Expand Up @@ -4534,7 +4541,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
if (Right.isPointerOrReference()) {
const FormatToken *Previous = &Left;
while (Previous && Previous->isNot(tok::kw_operator)) {
if (Previous->is(tok::identifier) || Previous->isTypeName(IsCpp)) {
if (Previous->is(tok::identifier) || Previous->isTypeName(LangOpts)) {
Previous = Previous->getPreviousNonComment();
continue;
}
Expand Down Expand Up @@ -4723,7 +4730,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
if (!Style.isVerilog() &&
(Left.isOneOf(tok::identifier, tok::greater, tok::r_square,
tok::r_paren) ||
Left.isTypeName(IsCpp)) &&
Left.isTypeName(LangOpts)) &&
Right.is(tok::l_brace) && Right.getNextNonComment() &&
Right.isNot(BK_Block)) {
return false;
Expand Down
6 changes: 5 additions & 1 deletion clang/lib/Format/TokenAnnotator.h
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,10 @@ class AnnotatedLine {
class TokenAnnotator {
public:
TokenAnnotator(const FormatStyle &Style, const AdditionalKeywords &Keywords)
: Style(Style), IsCpp(Style.isCpp()), Keywords(Keywords) {}
: Style(Style), IsCpp(Style.isCpp()),
LangOpts(getFormattingLangOpts(Style)), Keywords(Keywords) {
assert(IsCpp == LangOpts.CXXOperatorNames);
}

/// Adapts the indent levels of comment lines to the indent of the
/// subsequent line.
Expand Down Expand Up @@ -260,6 +263,7 @@ class TokenAnnotator {
const FormatStyle &Style;

bool IsCpp;
LangOptions LangOpts;

const AdditionalKeywords &Keywords;

Expand Down
21 changes: 12 additions & 9 deletions clang/lib/Format/UnwrappedLineParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,13 +160,16 @@ UnwrappedLineParser::UnwrappedLineParser(
IdentifierTable &IdentTable)
: Line(new UnwrappedLine), MustBreakBeforeNextToken(false),
CurrentLines(&Lines), Style(Style), IsCpp(Style.isCpp()),
Keywords(Keywords), CommentPragmasRegex(Style.CommentPragmas),
Tokens(nullptr), Callback(Callback), AllTokens(Tokens), PPBranchLevel(-1),
LangOpts(getFormattingLangOpts(Style)), Keywords(Keywords),
CommentPragmasRegex(Style.CommentPragmas), Tokens(nullptr),
Callback(Callback), AllTokens(Tokens), PPBranchLevel(-1),
IncludeGuard(Style.IndentPPDirectives == FormatStyle::PPDIS_None
? IG_Rejected
: IG_Inited),
IncludeGuardToken(nullptr), FirstStartColumn(FirstStartColumn),
Macros(Style.Macros, SourceMgr, Style, Allocator, IdentTable) {}
Macros(Style.Macros, SourceMgr, Style, Allocator, IdentTable) {
assert(IsCpp == LangOpts.CXXOperatorNames);
}

void UnwrappedLineParser::reset() {
PPBranchLevel = -1;
Expand Down Expand Up @@ -1870,7 +1873,7 @@ void UnwrappedLineParser::parseStructuralElement(
case tok::caret:
nextToken();
// Block return type.
if (FormatTok->Tok.isAnyIdentifier() || FormatTok->isTypeName(IsCpp)) {
if (FormatTok->Tok.isAnyIdentifier() || FormatTok->isTypeName(LangOpts)) {
nextToken();
// Return types: pointers are ok too.
while (FormatTok->is(tok::star))
Expand Down Expand Up @@ -2231,7 +2234,7 @@ bool UnwrappedLineParser::tryToParseLambda() {
bool InTemplateParameterList = false;

while (FormatTok->isNot(tok::l_brace)) {
if (FormatTok->isTypeName(IsCpp)) {
if (FormatTok->isTypeName(LangOpts)) {
nextToken();
continue;
}
Expand Down Expand Up @@ -3385,7 +3388,7 @@ void UnwrappedLineParser::parseAccessSpecifier() {
/// \brief Parses a requires, decides if it is a clause or an expression.
/// \pre The current token has to be the requires keyword.
/// \returns true if it parsed a clause.
bool clang::format::UnwrappedLineParser::parseRequires() {
bool UnwrappedLineParser::parseRequires() {
assert(FormatTok->is(tok::kw_requires) && "'requires' expected");
auto RequiresToken = FormatTok;

Expand Down Expand Up @@ -3448,7 +3451,7 @@ bool clang::format::UnwrappedLineParser::parseRequires() {
break;
}
default:
if (PreviousNonComment->isTypeOrIdentifier(IsCpp)) {
if (PreviousNonComment->isTypeOrIdentifier(LangOpts)) {
// This is a requires clause.
parseRequiresClause(RequiresToken);
return true;
Expand Down Expand Up @@ -3511,7 +3514,7 @@ bool clang::format::UnwrappedLineParser::parseRequires() {
--OpenAngles;
break;
default:
if (NextToken->isTypeName(IsCpp)) {
if (NextToken->isTypeName(LangOpts)) {
FormatTok = Tokens->setPosition(StoredPosition);
parseRequiresExpression(RequiresToken);
return false;
Expand Down Expand Up @@ -4027,7 +4030,7 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
if (FormatTok->is(tok::l_square)) {
FormatToken *Previous = FormatTok->Previous;
if (!Previous || (Previous->isNot(tok::r_paren) &&
!Previous->isTypeOrIdentifier(IsCpp))) {
!Previous->isTypeOrIdentifier(LangOpts))) {
// Don't try parsing a lambda if we had a closing parenthesis before,
// it was probably a pointer to an array: int (*)[].
if (!tryToParseLambda())
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Format/UnwrappedLineParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@ class UnwrappedLineParser {

const FormatStyle &Style;
bool IsCpp;
LangOptions LangOpts;
const AdditionalKeywords &Keywords;

llvm::Regex CommentPragmasRegex;
Expand Down
20 changes: 20 additions & 0 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3346,11 +3346,31 @@ static void GeneratePointerAuthArgs(const LangOptions &Opts,
ArgumentConsumer Consumer) {
if (Opts.PointerAuthIntrinsics)
GenerateArg(Consumer, OPT_fptrauth_intrinsics);
if (Opts.PointerAuthCalls)
GenerateArg(Consumer, OPT_fptrauth_calls);
if (Opts.PointerAuthReturns)
GenerateArg(Consumer, OPT_fptrauth_returns);
if (Opts.PointerAuthAuthTraps)
GenerateArg(Consumer, OPT_fptrauth_auth_traps);
if (Opts.PointerAuthVTPtrAddressDiscrimination)
GenerateArg(Consumer, OPT_fptrauth_vtable_pointer_address_discrimination);
if (Opts.PointerAuthVTPtrTypeDiscrimination)
GenerateArg(Consumer, OPT_fptrauth_vtable_pointer_type_discrimination);
if (Opts.PointerAuthInitFini)
GenerateArg(Consumer, OPT_fptrauth_init_fini);
}

static void ParsePointerAuthArgs(LangOptions &Opts, ArgList &Args,
DiagnosticsEngine &Diags) {
Opts.PointerAuthIntrinsics = Args.hasArg(OPT_fptrauth_intrinsics);
Opts.PointerAuthCalls = Args.hasArg(OPT_fptrauth_calls);
Opts.PointerAuthReturns = Args.hasArg(OPT_fptrauth_returns);
Opts.PointerAuthAuthTraps = Args.hasArg(OPT_fptrauth_auth_traps);
Opts.PointerAuthVTPtrAddressDiscrimination =
Args.hasArg(OPT_fptrauth_vtable_pointer_address_discrimination);
Opts.PointerAuthVTPtrTypeDiscrimination =
Args.hasArg(OPT_fptrauth_vtable_pointer_type_discrimination);
Opts.PointerAuthInitFini = Args.hasArg(OPT_fptrauth_init_fini);
}

/// Check if input file kind and language standard are compatible.
Expand Down
2 changes: 0 additions & 2 deletions clang/lib/Lex/PPMacroExpansion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1714,8 +1714,6 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
return llvm::StringSwitch<bool>(II->getName())
.Case("__array_rank", true)
.Case("__array_extent", true)
.Case("__reference_binds_to_temporary", true)
.Case("__reference_constructs_from_temporary", true)
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) .Case("__" #Trait, true)
#include "clang/Basic/TransformTypeTraits.def"
.Default(false);
Expand Down
28 changes: 15 additions & 13 deletions clang/lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2587,25 +2587,30 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
Parser &P;
Declarator &D;
Decl *ThisDecl;
bool Entered;

InitializerScopeRAII(Parser &P, Declarator &D, Decl *ThisDecl)
: P(P), D(D), ThisDecl(ThisDecl) {
: P(P), D(D), ThisDecl(ThisDecl), Entered(false) {
if (ThisDecl && P.getLangOpts().CPlusPlus) {
Scope *S = nullptr;
if (D.getCXXScopeSpec().isSet()) {
P.EnterScope(0);
S = P.getCurScope();
}
P.Actions.ActOnCXXEnterDeclInitializer(S, ThisDecl);
if (ThisDecl && !ThisDecl->isInvalidDecl()) {
P.Actions.ActOnCXXEnterDeclInitializer(S, ThisDecl);
Entered = true;
}
}
}
~InitializerScopeRAII() { pop(); }
void pop() {
~InitializerScopeRAII() {
if (ThisDecl && P.getLangOpts().CPlusPlus) {
Scope *S = nullptr;
if (D.getCXXScopeSpec().isSet())
S = P.getCurScope();
P.Actions.ActOnCXXExitDeclInitializer(S, ThisDecl);

if (Entered)
P.Actions.ActOnCXXExitDeclInitializer(S, ThisDecl);
if (S)
P.ExitScope();
}
Expand Down Expand Up @@ -2736,8 +2741,6 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
FRI->RangeExpr = Init;
}

InitScope.pop();

if (Init.isInvalid()) {
SmallVector<tok::TokenKind, 2> StopTokens;
StopTokens.push_back(tok::comma);
Expand Down Expand Up @@ -2785,8 +2788,6 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(

bool SawError = ParseExpressionList(Exprs, ExpressionStarts);

InitScope.pop();

if (SawError) {
if (ThisVarDecl && PP.isCodeCompletionReached() && !CalledSignatureHelp) {
Actions.ProduceConstructorSignatureHelp(
Expand Down Expand Up @@ -2818,8 +2819,6 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
PreferredType.enterVariableInit(Tok.getLocation(), ThisDecl);
ExprResult Init(ParseBraceInitializer());

InitScope.pop();

if (Init.isInvalid()) {
Actions.ActOnInitializerError(ThisDecl);
} else
Expand Down Expand Up @@ -4332,9 +4331,12 @@ void Parser::ParseDeclarationSpecifiers(

// friend
case tok::kw_friend:
if (DSContext == DeclSpecContext::DSC_class)
if (DSContext == DeclSpecContext::DSC_class) {
isInvalid = DS.SetFriendSpec(Loc, PrevSpec, DiagID);
else {
Scope *CurS = getCurScope();
if (!isInvalid && CurS)
CurS->setFlags(CurS->getFlags() | Scope::FriendScope);
} else {
PrevSpec = ""; // not actually used by the diagnostic
DiagID = diag::err_friend_invalid_in_context;
isInvalid = true;
Expand Down
5 changes: 2 additions & 3 deletions clang/lib/Parse/ParseDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1779,9 +1779,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
tok::kw___is_union,
tok::kw___is_unsigned,
tok::kw___is_void,
tok::kw___is_volatile,
tok::kw___reference_binds_to_temporary,
tok::kw___reference_constructs_from_temporary))
tok::kw___is_volatile
))
// GNU libstdc++ 4.2 and libc++ use certain intrinsic names as the
// name of struct templates, but some are keywords in GCC >= 4.3
// and Clang. Therefore, when we see the token sequence "struct
Expand Down
1 change: 0 additions & 1 deletion clang/lib/Parse/ParseExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1166,7 +1166,6 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
REVERTIBLE_TYPE_TRAIT(__is_void);
REVERTIBLE_TYPE_TRAIT(__is_volatile);
REVERTIBLE_TYPE_TRAIT(__reference_binds_to_temporary);
REVERTIBLE_TYPE_TRAIT(__reference_constructs_from_temporary);
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) \
REVERTIBLE_TYPE_TRAIT(RTT_JOIN(__, Trait));
#include "clang/Basic/TransformTypeTraits.def"
Expand Down
88 changes: 88 additions & 0 deletions clang/lib/Parse/ParseHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,94 @@ void Parser::ParseHLSLAnnotations(ParsedAttributes &Attrs,
return;
}
} break;
case ParsedAttr::AT_HLSLPackOffset: {
// Parse 'packoffset( c[Subcomponent][.component] )'.
// Check '('.
if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after)) {
SkipUntil(tok::r_paren, StopAtSemi); // skip through )
return;
}
// Check c[Subcomponent] as an identifier.
if (!Tok.is(tok::identifier)) {
Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
SkipUntil(tok::r_paren, StopAtSemi); // skip through )
return;
}
StringRef OffsetStr = Tok.getIdentifierInfo()->getName();
SourceLocation SubComponentLoc = Tok.getLocation();
if (OffsetStr[0] != 'c') {
Diag(Tok.getLocation(), diag::err_hlsl_packoffset_invalid_reg)
<< OffsetStr;
SkipUntil(tok::r_paren, StopAtSemi); // skip through )
return;
}
OffsetStr = OffsetStr.substr(1);
unsigned SubComponent = 0;
if (!OffsetStr.empty()) {
// Make sure SubComponent is a number.
if (OffsetStr.getAsInteger(10, SubComponent)) {
Diag(SubComponentLoc.getLocWithOffset(1),
diag::err_hlsl_unsupported_register_number);
SkipUntil(tok::r_paren, StopAtSemi); // skip through )
return;
}
}
unsigned Component = 0;
ConsumeToken(); // consume identifier.
SourceLocation ComponentLoc;
if (Tok.is(tok::period)) {
ConsumeToken(); // consume period.
if (!Tok.is(tok::identifier)) {
Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
SkipUntil(tok::r_paren, StopAtSemi); // skip through )
return;
}
StringRef ComponentStr = Tok.getIdentifierInfo()->getName();
ComponentLoc = Tok.getLocation();
ConsumeToken(); // consume identifier.
// Make sure Component is a single character.
if (ComponentStr.size() != 1) {
Diag(ComponentLoc, diag::err_hlsl_unsupported_component)
<< ComponentStr;
SkipUntil(tok::r_paren, StopAtSemi); // skip through )
return;
}
switch (ComponentStr[0]) {
case 'x':
case 'r':
Component = 0;
break;
case 'y':
case 'g':
Component = 1;
break;
case 'z':
case 'b':
Component = 2;
break;
case 'w':
case 'a':
Component = 3;
break;
default:
Diag(ComponentLoc, diag::err_hlsl_unsupported_component)
<< ComponentStr;
SkipUntil(tok::r_paren, StopAtSemi); // skip through )
return;
}
}
ASTContext &Ctx = Actions.getASTContext();
QualType SizeTy = Ctx.getSizeType();
uint64_t SizeTySize = Ctx.getTypeSize(SizeTy);
ArgExprs.push_back(IntegerLiteral::Create(
Ctx, llvm::APInt(SizeTySize, SubComponent), SizeTy, SubComponentLoc));
ArgExprs.push_back(IntegerLiteral::Create(
Ctx, llvm::APInt(SizeTySize, Component), SizeTy, ComponentLoc));
if (ExpectAndConsume(tok::r_paren, diag::err_expected)) {
SkipUntil(tok::r_paren, StopAtSemi); // skip through )
return;
}
} break;
case ParsedAttr::UnknownAttribute:
Diag(Loc, diag::err_unknown_hlsl_semantic) << II;
return;
Expand Down
61 changes: 43 additions & 18 deletions clang/lib/Parse/ParseOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -867,7 +867,6 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(
SemaOpenACC::OpenACCParsedClause ParsedClause(DirKind, ClauseKind, ClauseLoc);

if (ClauseHasRequiredParens(DirKind, ClauseKind)) {
ParsedClause.setLParenLoc(getCurToken().getLocation());
if (Parens.expectAndConsume()) {
// We are missing a paren, so assume that the person just forgot the
// parameter. Return 'false' so we try to continue on and parse the next
Expand All @@ -876,6 +875,7 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(
Parser::StopBeforeMatch);
return OpenACCCanContinue();
}
ParsedClause.setLParenLoc(Parens.getOpenLocation());

switch (ClauseKind) {
case OpenACCClauseKind::Default: {
Expand Down Expand Up @@ -956,7 +956,6 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(
break;
case OpenACCClauseKind::Attach:
case OpenACCClauseKind::DevicePtr:
// TODO: ERICH: Figure out how to limit to just ptrs?
ParsedClause.setVarListDetails(ParseOpenACCVarList(),
/*IsReadOnly=*/false, /*IsZero=*/false);
break;
Expand Down Expand Up @@ -1048,8 +1047,8 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(
return OpenACCCannotContinue();

} else if (ClauseHasOptionalParens(DirKind, ClauseKind)) {
ParsedClause.setLParenLoc(getCurToken().getLocation());
if (!Parens.consumeOpen()) {
ParsedClause.setLParenLoc(Parens.getOpenLocation());
switch (ClauseKind) {
case OpenACCClauseKind::Self: {
assert(DirKind != OpenACCDirectiveKind::Update);
Expand Down Expand Up @@ -1099,19 +1098,29 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(
return OpenACCCanContinue();
}
break;
case OpenACCClauseKind::Wait:
if (ParseOpenACCWaitArgument(ClauseLoc,
/*IsDirective=*/false)) {
case OpenACCClauseKind::Wait: {
OpenACCWaitParseInfo Info =
ParseOpenACCWaitArgument(ClauseLoc,
/*IsDirective=*/false);
if (Info.Failed) {
Parens.skipToEnd();
return OpenACCCanContinue();
}

ParsedClause.setWaitDetails(Info.DevNumExpr, Info.QueuesLoc,
std::move(Info.QueueIdExprs));
break;
}
default:
llvm_unreachable("Not an optional parens type?");
}
ParsedClause.setEndLoc(getCurToken().getLocation());
if (Parens.consumeClose())
return OpenACCCannotContinue();
} else {
// If we have optional parens, make sure we set the end-location to the
// clause, as we are a 'single token' clause.
ParsedClause.setEndLoc(ClauseLoc);
}
}
return OpenACCSuccess(
Expand All @@ -1135,7 +1144,9 @@ Parser::ParseOpenACCAsyncArgument(OpenACCDirectiveKind DK, OpenACCClauseKind CK,
/// In this section and throughout the specification, the term wait-argument
/// means:
/// [ devnum : int-expr : ] [ queues : ] async-argument-list
bool Parser::ParseOpenACCWaitArgument(SourceLocation Loc, bool IsDirective) {
Parser::OpenACCWaitParseInfo
Parser::ParseOpenACCWaitArgument(SourceLocation Loc, bool IsDirective) {
OpenACCWaitParseInfo Result;
// [devnum : int-expr : ]
if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::DevNum, Tok) &&
NextToken().is(tok::colon)) {
Expand All @@ -1149,18 +1160,25 @@ bool Parser::ParseOpenACCWaitArgument(SourceLocation Loc, bool IsDirective) {
: OpenACCDirectiveKind::Invalid,
IsDirective ? OpenACCClauseKind::Invalid : OpenACCClauseKind::Wait,
Loc);
if (Res.first.isInvalid() && Res.second == OpenACCParseCanContinue::Cannot)
return true;
if (Res.first.isInvalid() &&
Res.second == OpenACCParseCanContinue::Cannot) {
Result.Failed = true;
return Result;
}

if (ExpectAndConsume(tok::colon))
return true;
if (ExpectAndConsume(tok::colon)) {
Result.Failed = true;
return Result;
}

Result.DevNumExpr = Res.first.get();
}

// [ queues : ]
if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Queues, Tok) &&
NextToken().is(tok::colon)) {
// Consume queues.
ConsumeToken();
Result.QueuesLoc = ConsumeToken();
// Consume colon.
ConsumeToken();
}
Expand All @@ -1172,8 +1190,10 @@ bool Parser::ParseOpenACCWaitArgument(SourceLocation Loc, bool IsDirective) {
bool FirstArg = true;
while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {
if (!FirstArg) {
if (ExpectAndConsume(tok::comma))
return true;
if (ExpectAndConsume(tok::comma)) {
Result.Failed = true;
return Result;
}
}
FirstArg = false;

Expand All @@ -1183,11 +1203,16 @@ bool Parser::ParseOpenACCWaitArgument(SourceLocation Loc, bool IsDirective) {
IsDirective ? OpenACCClauseKind::Invalid : OpenACCClauseKind::Wait,
Loc);

if (Res.first.isInvalid() && Res.second == OpenACCParseCanContinue::Cannot)
return true;
if (Res.first.isInvalid() &&
Res.second == OpenACCParseCanContinue::Cannot) {
Result.Failed = true;
return Result;
}

Result.QueueIdExprs.push_back(Res.first.get());
}

return false;
return Result;
}

ExprResult Parser::ParseOpenACCIDExpression() {
Expand Down Expand Up @@ -1356,7 +1381,7 @@ Parser::OpenACCDirectiveParseInfo Parser::ParseOpenACCDirective() {
break;
case OpenACCDirectiveKind::Wait:
// OpenACC has an optional paren-wrapped 'wait-argument'.
if (ParseOpenACCWaitArgument(StartLoc, /*IsDirective=*/true))
if (ParseOpenACCWaitArgument(StartLoc, /*IsDirective=*/true).Failed)
T.skipToEnd();
else
T.consumeClose();
Expand Down
51 changes: 8 additions & 43 deletions clang/lib/Parse/ParseOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4228,20 +4228,13 @@ bool Parser::parseMapperModifier(SemaOpenMP::OpenMPVarListDataTy &Data) {
return T.consumeClose();
}

static OpenMPMapClauseKind isMapType(Parser &P);

/// Parse map-type-modifiers in map clause.
/// map([ [map-type-modifier[,] [map-type-modifier[,] ...] [map-type] : ] list)
/// map([ [map-type-modifier[,] [map-type-modifier[,] ...] map-type : ] list)
/// where, map-type-modifier ::= always | close | mapper(mapper-identifier) |
/// present
/// where, map-type ::= alloc | delete | from | release | to | tofrom
bool Parser::parseMapTypeModifiers(SemaOpenMP::OpenMPVarListDataTy &Data) {
bool HasMapType = false;
SourceLocation PreMapLoc = Tok.getLocation();
StringRef PreMapName = "";
while (getCurToken().isNot(tok::colon)) {
OpenMPMapModifierKind TypeModifier = isMapModifier(*this);
OpenMPMapClauseKind MapKind = isMapType(*this);
if (TypeModifier == OMPC_MAP_MODIFIER_always ||
TypeModifier == OMPC_MAP_MODIFIER_close ||
TypeModifier == OMPC_MAP_MODIFIER_present ||
Expand All @@ -4264,19 +4257,6 @@ bool Parser::parseMapTypeModifiers(SemaOpenMP::OpenMPVarListDataTy &Data) {
Diag(Data.MapTypeModifiersLoc.back(), diag::err_omp_missing_comma)
<< "map type modifier";

} else if (getLangOpts().OpenMP >= 60 && MapKind != OMPC_MAP_unknown) {
if (!HasMapType) {
HasMapType = true;
Data.ExtraModifier = MapKind;
MapKind = OMPC_MAP_unknown;
PreMapLoc = Tok.getLocation();
PreMapName = Tok.getIdentifierInfo()->getName();
} else {
Diag(Tok, diag::err_omp_more_one_map_type);
Diag(PreMapLoc, diag::note_previous_map_type_specified_here)
<< PreMapName;
}
ConsumeToken();
} else {
// For the case of unknown map-type-modifier or a map-type.
// Map-type is followed by a colon; the function returns when it
Expand All @@ -4287,14 +4267,8 @@ bool Parser::parseMapTypeModifiers(SemaOpenMP::OpenMPVarListDataTy &Data) {
continue;
}
// Potential map-type token as it is followed by a colon.
if (PP.LookAhead(0).is(tok::colon)) {
if (getLangOpts().OpenMP >= 60) {
break;
} else {
return false;
}
}

if (PP.LookAhead(0).is(tok::colon))
return false;
Diag(Tok, diag::err_omp_unknown_map_type_modifier)
<< (getLangOpts().OpenMP >= 51 ? (getLangOpts().OpenMP >= 52 ? 2 : 1)
: 0)
Expand All @@ -4304,14 +4278,6 @@ bool Parser::parseMapTypeModifiers(SemaOpenMP::OpenMPVarListDataTy &Data) {
if (getCurToken().is(tok::comma))
ConsumeToken();
}
if (getLangOpts().OpenMP >= 60 && !HasMapType) {
if (!Tok.is(tok::colon)) {
Diag(Tok, diag::err_omp_unknown_map_type);
ConsumeToken();
} else {
Data.ExtraModifier = OMPC_MAP_unknown;
}
}
return false;
}

Expand All @@ -4323,12 +4289,13 @@ static OpenMPMapClauseKind isMapType(Parser &P) {
if (!Tok.isOneOf(tok::identifier, tok::kw_delete))
return OMPC_MAP_unknown;
Preprocessor &PP = P.getPreprocessor();
unsigned MapType =
getOpenMPSimpleClauseType(OMPC_map, PP.getSpelling(Tok), P.getLangOpts());
OpenMPMapClauseKind MapType =
static_cast<OpenMPMapClauseKind>(getOpenMPSimpleClauseType(
OMPC_map, PP.getSpelling(Tok), P.getLangOpts()));
if (MapType == OMPC_MAP_to || MapType == OMPC_MAP_from ||
MapType == OMPC_MAP_tofrom || MapType == OMPC_MAP_alloc ||
MapType == OMPC_MAP_delete || MapType == OMPC_MAP_release)
return static_cast<OpenMPMapClauseKind>(MapType);
return MapType;
return OMPC_MAP_unknown;
}

Expand Down Expand Up @@ -4712,10 +4679,8 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
// Only parse map-type-modifier[s] and map-type if a colon is present in
// the map clause.
if (ColonPresent) {
if (getLangOpts().OpenMP >= 60 && getCurToken().is(tok::colon))
Diag(Tok, diag::err_omp_map_modifier_specification_list);
IsInvalidMapperModifier = parseMapTypeModifiers(Data);
if (getLangOpts().OpenMP < 60 && !IsInvalidMapperModifier)
if (!IsInvalidMapperModifier)
parseMapType(*this, Data);
else
SkipUntil(tok::colon, tok::annot_pragma_openmp_end, StopBeforeMatch);
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Sema/Scope.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ void Scope::dumpImpl(raw_ostream &OS) const {
{ClassInheritanceScope, "ClassInheritanceScope"},
{CatchScope, "CatchScope"},
{OpenACCComputeConstructScope, "OpenACCComputeConstructScope"},
{FriendScope, "FriendScope"},
};

for (auto Info : FlagInfo) {
Expand Down
30 changes: 25 additions & 5 deletions clang/lib/Sema/SemaAccess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1473,12 +1473,32 @@ static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
// specifier, like this:
// A::private_type A::foo() { ... }
//
// Or we might be parsing something that will turn out to be a friend:
// void foo(A::private_type);
// void B::foo(A::private_type);
// friend declaration should not be delayed because it may lead to incorrect
// redeclaration chain, such as:
// class D {
// class E{
// class F{};
// friend void foo(D::E::F& q);
// };
// friend void foo(D::E::F& q);
// };
if (S.DelayedDiagnostics.shouldDelayDiagnostics()) {
S.DelayedDiagnostics.add(DelayedDiagnostic::makeAccess(Loc, Entity));
return Sema::AR_delayed;
// [class.friend]p9:
// A member nominated by a friend declaration shall be accessible in the
// class containing the friend declaration. The meaning of the friend
// declaration is the same whether the friend declaration appears in the
// private, protected, or public ([class.mem]) portion of the class
// member-specification.
Scope *TS = S.getCurScope();
bool IsFriendDeclaration = false;
while (TS && !IsFriendDeclaration) {
IsFriendDeclaration = TS->isFriendScope();
TS = TS->getParent();
}
if (!IsFriendDeclaration) {
S.DelayedDiagnostics.add(DelayedDiagnostic::makeAccess(Loc, Entity));
return Sema::AR_delayed;
}
}

EffectiveContext EC(S.CurContext);
Expand Down
9 changes: 4 additions & 5 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16574,11 +16574,10 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
std::string PrettySourceValue = toString(Value, 10);
std::string PrettyTargetValue = PrettyPrintInRange(Value, TargetRange);

S.DiagRuntimeBehavior(
E->getExprLoc(), E,
S.PDiag(diag::warn_impcast_integer_precision_constant)
<< PrettySourceValue << PrettyTargetValue << E->getType() << T
<< E->getSourceRange() << SourceRange(CC));
S.Diag(E->getExprLoc(),
S.PDiag(diag::warn_impcast_integer_precision_constant)
<< PrettySourceValue << PrettyTargetValue << E->getType()
<< T << E->getSourceRange() << SourceRange(CC));
return;
}
}
Expand Down
52 changes: 52 additions & 0 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7309,6 +7309,55 @@ static void handleHLSLSV_DispatchThreadIDAttr(Sema &S, Decl *D,
D->addAttr(::new (S.Context) HLSLSV_DispatchThreadIDAttr(S.Context, AL));
}

static void handleHLSLPackOffsetAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!isa<VarDecl>(D) || !isa<HLSLBufferDecl>(D->getDeclContext())) {
S.Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_ast_node)
<< AL << "shader constant in a constant buffer";
return;
}

uint32_t SubComponent;
if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), SubComponent))
return;
uint32_t Component;
if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(1), Component))
return;

QualType T = cast<VarDecl>(D)->getType().getCanonicalType();
// Check if T is an array or struct type.
// TODO: mark matrix type as aggregate type.
bool IsAggregateTy = (T->isArrayType() || T->isStructureType());

// Check Component is valid for T.
if (Component) {
unsigned Size = S.getASTContext().getTypeSize(T);
if (IsAggregateTy || Size > 128) {
S.Diag(AL.getLoc(), diag::err_hlsl_packoffset_cross_reg_boundary);
return;
} else {
// Make sure Component + sizeof(T) <= 4.
if ((Component * 32 + Size) > 128) {
S.Diag(AL.getLoc(), diag::err_hlsl_packoffset_cross_reg_boundary);
return;
}
QualType EltTy = T;
if (const auto *VT = T->getAs<VectorType>())
EltTy = VT->getElementType();
unsigned Align = S.getASTContext().getTypeAlign(EltTy);
if (Align > 32 && Component == 1) {
// NOTE: Component 3 will hit err_hlsl_packoffset_cross_reg_boundary.
// So we only need to check Component 1 here.
S.Diag(AL.getLoc(), diag::err_hlsl_packoffset_alignment_mismatch)
<< Align << EltTy;
return;
}
}
}

D->addAttr(::new (S.Context)
HLSLPackOffsetAttr(S.Context, AL, SubComponent, Component));
}

static void handleHLSLShaderAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
StringRef Str;
SourceLocation ArgLoc;
Expand Down Expand Up @@ -9730,6 +9779,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_HLSLSV_DispatchThreadID:
handleHLSLSV_DispatchThreadIDAttr(S, D, AL);
break;
case ParsedAttr::AT_HLSLPackOffset:
handleHLSLPackOffsetAttr(S, D, AL);
break;
case ParsedAttr::AT_HLSLShader:
handleHLSLShaderAttr(S, D, AL);
break;
Expand Down
53 changes: 29 additions & 24 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18553,15 +18553,6 @@ void Sema::ActOnPureSpecifier(Decl *D, SourceLocation ZeroLoc) {
Diag(D->getLocation(), diag::err_illegal_initializer);
}

/// Determine whether the given declaration is a global variable or
/// static data member.
static bool isNonlocalVariable(const Decl *D) {
if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(D))
return Var->hasGlobalStorage();

return false;
}

/// Invoked when we are about to parse an initializer for the declaration
/// 'Dcl'.
///
Expand All @@ -18570,9 +18561,7 @@ static bool isNonlocalVariable(const Decl *D) {
/// class X. If the declaration had a scope specifier, a scope will have
/// been created and passed in for this purpose. Otherwise, S will be null.
void Sema::ActOnCXXEnterDeclInitializer(Scope *S, Decl *D) {
// If there is no declaration, there was an error parsing it.
if (!D || D->isInvalidDecl())
return;
assert(D && !D->isInvalidDecl());

// We will always have a nested name specifier here, but this declaration
// might not be out of line if the specifier names the current namespace:
Expand All @@ -18581,25 +18570,41 @@ void Sema::ActOnCXXEnterDeclInitializer(Scope *S, Decl *D) {
if (S && D->isOutOfLine())
EnterDeclaratorContext(S, D->getDeclContext());

// If we are parsing the initializer for a static data member, push a
// new expression evaluation context that is associated with this static
// data member.
if (isNonlocalVariable(D))
PushExpressionEvaluationContext(
ExpressionEvaluationContext::PotentiallyEvaluated, D);
PushExpressionEvaluationContext(
ExpressionEvaluationContext::PotentiallyEvaluated, D);
}

/// Invoked after we are finished parsing an initializer for the declaration D.
void Sema::ActOnCXXExitDeclInitializer(Scope *S, Decl *D) {
// If there is no declaration, there was an error parsing it.
if (!D || D->isInvalidDecl())
return;

if (isNonlocalVariable(D))
PopExpressionEvaluationContext();
assert(D);

if (S && D->isOutOfLine())
ExitDeclaratorContext(S);

if (getLangOpts().CPlusPlus23) {
// An expression or conversion is 'manifestly constant-evaluated' if it is:
// [...]
// - the initializer of a variable that is usable in constant expressions or
// has constant initialization.
if (auto *VD = dyn_cast<VarDecl>(D);
VD && (VD->isUsableInConstantExpressions(Context) ||
VD->hasConstantInitialization())) {
// An expression or conversion is in an 'immediate function context' if it
// is potentially evaluated and either:
// [...]
// - it is a subexpression of a manifestly constant-evaluated expression
// or conversion.
ExprEvalContexts.back().InImmediateFunctionContext = true;
}
}

// Unless the initializer is in an immediate function context (as determined
// above), this will evaluate all contained immediate function calls as
// constant expressions. If the initializer IS an immediate function context,
// the initializer has been determined to be a constant expression, and all
// such evaluations will be elided (i.e., as if we "knew the whole time" that
// it was a constant expression).
PopExpressionEvaluationContext();
}

/// ActOnCXXConditionDeclarationExpr - Parsed a condition declaration of a
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18039,7 +18039,7 @@ HandleImmediateInvocations(Sema &SemaRef,
Sema::ExpressionEvaluationContextRecord &Rec) {
if ((Rec.ImmediateInvocationCandidates.size() == 0 &&
Rec.ReferenceToConsteval.size() == 0) ||
SemaRef.RebuildingImmediateInvocation)
Rec.isImmediateFunctionContext() || SemaRef.RebuildingImmediateInvocation)
return;

/// When we have more than 1 ImmediateInvocationCandidates or previously
Expand Down
159 changes: 92 additions & 67 deletions clang/lib/Sema/SemaExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5627,6 +5627,76 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceInfo *Lhs,
const TypeSourceInfo *Rhs, SourceLocation KeyLoc);

static ExprResult CheckConvertibilityForTypeTraits(
Sema &Self, const TypeSourceInfo *Lhs, const TypeSourceInfo *Rhs,
SourceLocation KeyLoc, llvm::BumpPtrAllocator &OpaqueExprAllocator) {

QualType LhsT = Lhs->getType();
QualType RhsT = Rhs->getType();

// C++0x [meta.rel]p4:
// Given the following function prototype:
//
// template <class T>
// typename add_rvalue_reference<T>::type create();
//
// the predicate condition for a template specialization
// is_convertible<From, To> shall be satisfied if and only if
// the return expression in the following code would be
// well-formed, including any implicit conversions to the return
// type of the function:
//
// To test() {
// return create<From>();
// }
//
// Access checking is performed as if in a context unrelated to To and
// From. Only the validity of the immediate context of the expression
// of the return-statement (including conversions to the return type)
// is considered.
//
// We model the initialization as a copy-initialization of a temporary
// of the appropriate type, which for this expression is identical to the
// return statement (since NRVO doesn't apply).

// Functions aren't allowed to return function or array types.
if (RhsT->isFunctionType() || RhsT->isArrayType())
return ExprError();

// A function definition requires a complete, non-abstract return type.
if (!Self.isCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT) ||
Self.isAbstractType(Rhs->getTypeLoc().getBeginLoc(), RhsT))
return ExprError();

// Compute the result of add_rvalue_reference.
if (LhsT->isObjectType() || LhsT->isFunctionType())
LhsT = Self.Context.getRValueReferenceType(LhsT);

// Build a fake source and destination for initialization.
InitializedEntity To(InitializedEntity::InitializeTemporary(RhsT));
Expr *From = new (OpaqueExprAllocator.Allocate<OpaqueValueExpr>())
OpaqueValueExpr(KeyLoc, LhsT.getNonLValueExprType(Self.Context),
Expr::getValueKindForType(LhsT));
InitializationKind Kind =
InitializationKind::CreateCopy(KeyLoc, SourceLocation());

// Perform the initialization in an unevaluated context within a SFINAE
// trap at translation unit scope.
EnterExpressionEvaluationContext Unevaluated(
Self, Sema::ExpressionEvaluationContext::Unevaluated);
Sema::SFINAETrap SFINAE(Self, /*AccessCheckingSFINAE=*/true);
Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl());
InitializationSequence Init(Self, To, Kind, From);
if (Init.Failed())
return ExprError();

ExprResult Result = Init.Perform(Self, To, Kind, From);
if (Result.isInvalid() || SFINAE.hasErrorOccurred())
return ExprError();

return Result;
}

static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind,
SourceLocation KWLoc,
ArrayRef<TypeSourceInfo *> Args,
Expand All @@ -5640,13 +5710,16 @@ static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind,

// Evaluate ReferenceBindsToTemporary and ReferenceConstructsFromTemporary
// alongside the IsConstructible traits to avoid duplication.
if (Kind <= BTT_Last && Kind != BTT_ReferenceBindsToTemporary && Kind != BTT_ReferenceConstructsFromTemporary)
if (Kind <= BTT_Last && Kind != BTT_ReferenceBindsToTemporary &&
Kind != BTT_ReferenceConstructsFromTemporary &&
Kind != BTT_ReferenceConvertsFromTemporary)
return EvaluateBinaryTypeTrait(S, Kind, Args[0],
Args[1], RParenLoc);

switch (Kind) {
case clang::BTT_ReferenceBindsToTemporary:
case clang::BTT_ReferenceConstructsFromTemporary:
case clang::BTT_ReferenceConvertsFromTemporary:
case clang::TT_IsConstructible:
case clang::TT_IsNothrowConstructible:
case clang::TT_IsTriviallyConstructible: {
Expand Down Expand Up @@ -5710,8 +5783,10 @@ static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind,
Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl());
InitializedEntity To(
InitializedEntity::InitializeTemporary(S.Context, Args[0]));
InitializationKind InitKind(InitializationKind::CreateDirect(KWLoc, KWLoc,
RParenLoc));
InitializationKind InitKind(
Kind == clang::BTT_ReferenceConvertsFromTemporary
? InitializationKind::CreateCopy(KWLoc, KWLoc)
: InitializationKind::CreateDirect(KWLoc, KWLoc, RParenLoc));
InitializationSequence Init(S, To, InitKind, ArgExprs);
if (Init.Failed())
return false;
Expand All @@ -5723,7 +5798,9 @@ static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind,
if (Kind == clang::TT_IsConstructible)
return true;

if (Kind == clang::BTT_ReferenceBindsToTemporary || Kind == clang::BTT_ReferenceConstructsFromTemporary) {
if (Kind == clang::BTT_ReferenceBindsToTemporary ||
Kind == clang::BTT_ReferenceConstructsFromTemporary ||
Kind == clang::BTT_ReferenceConvertsFromTemporary) {
if (!T->isReferenceType())
return false;

Expand All @@ -5737,9 +5814,13 @@ static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind,
if (U->isReferenceType())
return false;

TypeSourceInfo *TPtr = S.Context.CreateTypeSourceInfo(S.Context.getPointerType(S.BuiltinRemoveReference(T, UnaryTransformType::RemoveCVRef, {})));
TypeSourceInfo *UPtr = S.Context.CreateTypeSourceInfo(S.Context.getPointerType(S.BuiltinRemoveReference(U, UnaryTransformType::RemoveCVRef, {})));
return EvaluateBinaryTypeTrait(S, TypeTrait::BTT_IsConvertibleTo, UPtr, TPtr, RParenLoc);
TypeSourceInfo *TPtr = S.Context.CreateTypeSourceInfo(
S.Context.getPointerType(T.getNonReferenceType()));
TypeSourceInfo *UPtr = S.Context.CreateTypeSourceInfo(
S.Context.getPointerType(U.getNonReferenceType()));
return !CheckConvertibilityForTypeTraits(S, UPtr, TPtr, RParenLoc,
OpaqueExprAllocator)
.isInvalid();
}

if (Kind == clang::TT_IsNothrowConstructible)
Expand Down Expand Up @@ -5945,68 +6026,12 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceI
case BTT_IsConvertible:
case BTT_IsConvertibleTo:
case BTT_IsNothrowConvertible: {
// C++0x [meta.rel]p4:
// Given the following function prototype:
//
// template <class T>
// typename add_rvalue_reference<T>::type create();
//
// the predicate condition for a template specialization
// is_convertible<From, To> shall be satisfied if and only if
// the return expression in the following code would be
// well-formed, including any implicit conversions to the return
// type of the function:
//
// To test() {
// return create<From>();
// }
//
// Access checking is performed as if in a context unrelated to To and
// From. Only the validity of the immediate context of the expression
// of the return-statement (including conversions to the return type)
// is considered.
//
// We model the initialization as a copy-initialization of a temporary
// of the appropriate type, which for this expression is identical to the
// return statement (since NRVO doesn't apply).

// Functions aren't allowed to return function or array types.
if (RhsT->isFunctionType() || RhsT->isArrayType())
return false;

// A return statement in a void function must have void type.
if (RhsT->isVoidType())
return LhsT->isVoidType();

// A function definition requires a complete, non-abstract return type.
if (!Self.isCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT) ||
Self.isAbstractType(Rhs->getTypeLoc().getBeginLoc(), RhsT))
return false;

// Compute the result of add_rvalue_reference.
if (LhsT->isObjectType() || LhsT->isFunctionType())
LhsT = Self.Context.getRValueReferenceType(LhsT);

// Build a fake source and destination for initialization.
InitializedEntity To(InitializedEntity::InitializeTemporary(RhsT));
OpaqueValueExpr From(KeyLoc, LhsT.getNonLValueExprType(Self.Context),
Expr::getValueKindForType(LhsT));
Expr *FromPtr = &From;
InitializationKind Kind(InitializationKind::CreateCopy(KeyLoc,
SourceLocation()));

// Perform the initialization in an unevaluated context within a SFINAE
// trap at translation unit scope.
EnterExpressionEvaluationContext Unevaluated(
Self, Sema::ExpressionEvaluationContext::Unevaluated);
Sema::SFINAETrap SFINAE(Self, /*AccessCheckingSFINAE=*/true);
Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl());
InitializationSequence Init(Self, To, Kind, FromPtr);
if (Init.Failed())
return false;

ExprResult Result = Init.Perform(Self, To, Kind, FromPtr);
if (Result.isInvalid() || SFINAE.hasErrorOccurred())
llvm::BumpPtrAllocator OpaqueExprAllocator;
ExprResult Result = CheckConvertibilityForTypeTraits(Self, Lhs, Rhs, KeyLoc,
OpaqueExprAllocator);
if (Result.isInvalid())
return false;

if (BTT != BTT_IsNothrowConvertible)
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Sema/SemaExprMember.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -996,7 +996,10 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
// build a CXXDependentScopeMemberExpr.
if (R.wasNotFoundInCurrentInstantiation() ||
(IsArrow && !BaseExprType->isPointerType() &&
BaseExprType->isDependentType()))
BaseExprType->isDependentType()) ||
(R.getLookupName().getCXXOverloadedOperator() == OO_Equal &&
(SS.isSet() ? SS.getScopeRep()->isDependent()
: BaseExprType->isDependentType())))
return ActOnDependentMemberExpr(BaseExpr, BaseExprType, IsArrow, OpLoc, SS,
TemplateKWLoc, FirstQualifierInScope,
R.getLookupNameInfo(), TemplateArgs);
Expand Down
80 changes: 80 additions & 0 deletions clang/lib/Sema/SemaHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,89 @@ Decl *SemaHLSL::ActOnStartBuffer(Scope *BufferScope, bool CBuffer,
return Result;
}

// Calculate the size of a legacy cbuffer type based on
// https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-packing-rules
static unsigned calculateLegacyCbufferSize(const ASTContext &Context,
QualType T) {
unsigned Size = 0;
constexpr unsigned CBufferAlign = 128;
if (const RecordType *RT = T->getAs<RecordType>()) {
const RecordDecl *RD = RT->getDecl();
for (const FieldDecl *Field : RD->fields()) {
QualType Ty = Field->getType();
unsigned FieldSize = calculateLegacyCbufferSize(Context, Ty);
unsigned FieldAlign = 32;
if (Ty->isAggregateType())
FieldAlign = CBufferAlign;
Size = llvm::alignTo(Size, FieldAlign);
Size += FieldSize;
}
} else if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) {
if (unsigned ElementCount = AT->getSize().getZExtValue()) {
unsigned ElementSize =
calculateLegacyCbufferSize(Context, AT->getElementType());
unsigned AlignedElementSize = llvm::alignTo(ElementSize, CBufferAlign);
Size = AlignedElementSize * (ElementCount - 1) + ElementSize;
}
} else if (const VectorType *VT = T->getAs<VectorType>()) {
unsigned ElementCount = VT->getNumElements();
unsigned ElementSize =
calculateLegacyCbufferSize(Context, VT->getElementType());
Size = ElementSize * ElementCount;
} else {
Size = Context.getTypeSize(T);
}
return Size;
}

void SemaHLSL::ActOnFinishBuffer(Decl *Dcl, SourceLocation RBrace) {
auto *BufDecl = cast<HLSLBufferDecl>(Dcl);
BufDecl->setRBraceLoc(RBrace);

// Validate packoffset.
llvm::SmallVector<std::pair<VarDecl *, HLSLPackOffsetAttr *>> PackOffsetVec;
bool HasPackOffset = false;
bool HasNonPackOffset = false;
for (auto *Field : BufDecl->decls()) {
VarDecl *Var = dyn_cast<VarDecl>(Field);
if (!Var)
continue;
if (Field->hasAttr<HLSLPackOffsetAttr>()) {
PackOffsetVec.emplace_back(Var, Field->getAttr<HLSLPackOffsetAttr>());
HasPackOffset = true;
} else {
HasNonPackOffset = true;
}
}

if (HasPackOffset && HasNonPackOffset)
Diag(BufDecl->getLocation(), diag::warn_hlsl_packoffset_mix);

if (HasPackOffset) {
ASTContext &Context = getASTContext();
// Make sure no overlap in packoffset.
// Sort PackOffsetVec by offset.
std::sort(PackOffsetVec.begin(), PackOffsetVec.end(),
[](const std::pair<VarDecl *, HLSLPackOffsetAttr *> &LHS,
const std::pair<VarDecl *, HLSLPackOffsetAttr *> &RHS) {
return LHS.second->getOffset() < RHS.second->getOffset();
});

for (unsigned i = 0; i < PackOffsetVec.size() - 1; i++) {
VarDecl *Var = PackOffsetVec[i].first;
HLSLPackOffsetAttr *Attr = PackOffsetVec[i].second;
unsigned Size = calculateLegacyCbufferSize(Context, Var->getType());
unsigned Begin = Attr->getOffset() * 32;
unsigned End = Begin + Size;
unsigned NextBegin = PackOffsetVec[i + 1].second->getOffset() * 32;
if (End > NextBegin) {
VarDecl *NextVar = PackOffsetVec[i + 1].first;
Diag(NextVar->getLocation(), diag::err_hlsl_packoffset_overlap)
<< NextVar << Var;
}
}
}

SemaRef.PopDeclContext();
}

Expand Down
28 changes: 8 additions & 20 deletions clang/lib/Sema/SemaLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1282,6 +1282,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
if (DeclContext *DC = PreS->getEntity())
DeclareImplicitMemberFunctionsWithName(*this, Name, R.getNameLoc(), DC);
}

// C++23 [temp.dep.general]p2:
// The component name of an unqualified-id is dependent if
// - it is a conversion-function-id whose conversion-type-id
Expand All @@ -1294,21 +1295,6 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
return false;
}

// If this is the name of an implicitly-declared special member function,
// go through the scope stack to implicitly declare
if (isImplicitlyDeclaredMemberFunctionName(Name)) {
for (Scope *PreS = S; PreS; PreS = PreS->getParent())
if (DeclContext *DC = PreS->getEntity()) {
if (DC->isDependentContext() && isa<CXXRecordDecl>(DC) &&
Name.getCXXOverloadedOperator() == OO_Equal &&
!R.isTemplateNameLookup()) {
R.setNotFoundInCurrentInstantiation();
return false;
}
DeclareImplicitMemberFunctionsWithName(*this, Name, R.getNameLoc(), DC);
}
}

// Implicitly declare member functions with the name we're looking for, if in
// fact we are in a scope where it matters.

Expand Down Expand Up @@ -2472,8 +2458,10 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
}
} QL(LookupCtx);

bool TemplateNameLookup = R.isTemplateNameLookup();
CXXRecordDecl *LookupRec = dyn_cast<CXXRecordDecl>(LookupCtx);
// FIXME: Per [temp.dep.general]p2, an unqualified name is also dependent
// if it's a dependent conversion-function-id or operator= where the current
// class is a templated entity. This should be handled in LookupName.
if (!InUnqualifiedLookup && !R.isForRedeclaration()) {
// C++23 [temp.dep.type]p5:
// A qualified name is dependent if
Expand All @@ -2484,10 +2472,8 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
// is operator=, or
// - [...]
if (DeclarationName Name = R.getLookupName();
(Name.getNameKind() == DeclarationName::CXXConversionFunctionName &&
Name.getCXXNameType()->isDependentType()) ||
(Name.getCXXOverloadedOperator() == OO_Equal && LookupRec &&
LookupRec->isDependentContext() && !TemplateNameLookup)) {
Name.getNameKind() == DeclarationName::CXXConversionFunctionName &&
Name.getCXXNameType()->isDependentType()) {
R.setNotFoundInCurrentInstantiation();
return false;
}
Expand Down Expand Up @@ -2583,6 +2569,8 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
return true;
};

bool TemplateNameLookup = R.isTemplateNameLookup();

// Determine whether two sets of members contain the same members, as
// required by C++ [class.member.lookup]p6.
auto HasSameDeclarations = [&](DeclContext::lookup_iterator A,
Expand Down
28 changes: 28 additions & 0 deletions clang/lib/Sema/SemaOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,22 @@ bool doesClauseApplyToDirective(OpenACCDirectiveKind DirectiveKind,
default:
return false;
}
case OpenACCClauseKind::Wait:
switch (DirectiveKind) {
case OpenACCDirectiveKind::Parallel:
case OpenACCDirectiveKind::Serial:
case OpenACCDirectiveKind::Kernels:
case OpenACCDirectiveKind::Data:
case OpenACCDirectiveKind::EnterData:
case OpenACCDirectiveKind::ExitData:
case OpenACCDirectiveKind::Update:
case OpenACCDirectiveKind::ParallelLoop:
case OpenACCDirectiveKind::SerialLoop:
case OpenACCDirectiveKind::KernelsLoop:
return true;
default:
return false;
}

default:
// Do nothing so we can go to the 'unimplemented' diagnostic instead.
Expand Down Expand Up @@ -623,6 +639,18 @@ SemaOpenACC::ActOnClause(ArrayRef<const OpenACCClause *> ExistingClauses,
getASTContext(), Clause.getBeginLoc(), Clause.getLParenLoc(),
Clause.getVarList(), Clause.getEndLoc());
}
case OpenACCClauseKind::Wait: {
// Restrictions only properly implemented on 'compute' constructs, and
// 'compute' constructs are the only construct that can do anything with
// this yet, so skip/treat as unimplemented in this case.
if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
break;

return OpenACCWaitClause::Create(
getASTContext(), Clause.getBeginLoc(), Clause.getLParenLoc(),
Clause.getDevNumExpr(), Clause.getQueuesLoc(), Clause.getQueueIdExprs(),
Clause.getEndLoc());
}
default:
break;
}
Expand Down
28 changes: 21 additions & 7 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -750,7 +750,8 @@ Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS,
if (!MightBeCxx11UnevalField && !isAddressOfOperand && !IsEnum &&
isa<CXXMethodDecl>(DC) &&
cast<CXXMethodDecl>(DC)->isImplicitObjectMemberFunction()) {
QualType ThisType = cast<CXXMethodDecl>(DC)->getThisType().getNonReferenceType();
QualType ThisType =
cast<CXXMethodDecl>(DC)->getThisType().getNonReferenceType();

// Since the 'this' expression is synthesized, we don't need to
// perform the double-lookup check.
Expand Down Expand Up @@ -2491,9 +2492,6 @@ struct ConvertConstructorToDeductionGuideTransform {
Args.addOuterRetainedLevel();
}

if (NestedPattern)
Args.addOuterRetainedLevels(NestedPattern->getTemplateDepth());

FunctionProtoTypeLoc FPTL = CD->getTypeSourceInfo()->getTypeLoc()
.getAsAdjusted<FunctionProtoTypeLoc>();
assert(FPTL && "no prototype for constructor declaration");
Expand Down Expand Up @@ -2583,11 +2581,27 @@ struct ConvertConstructorToDeductionGuideTransform {

// -- The types of the function parameters are those of the constructor.
for (auto *OldParam : TL.getParams()) {
ParmVarDecl *NewParam =
transformFunctionTypeParam(OldParam, Args, MaterializedTypedefs);
if (NestedPattern && NewParam)
ParmVarDecl *NewParam = OldParam;
// Given
// template <class T> struct C {
// template <class U> struct D {
// template <class V> D(U, V);
// };
// };
// First, transform all the references to template parameters that are
// defined outside of the surrounding class template. That is T in the
// above example.
if (NestedPattern) {
NewParam = transformFunctionTypeParam(NewParam, OuterInstantiationArgs,
MaterializedTypedefs);
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);
if (!NewParam)
return QualType();
ParamTypes.push_back(NewParam->getType());
Expand Down
45 changes: 45 additions & 0 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -11425,6 +11425,51 @@ void OpenACCClauseTransform<Derived>::VisitAsyncClause(
: nullptr,
ParsedClause.getEndLoc());
}
template <typename Derived>
void OpenACCClauseTransform<Derived>::VisitWaitClause(
const OpenACCWaitClause &C) {
if (!C.getLParenLoc().isInvalid()) {
Expr *DevNumExpr = nullptr;
llvm::SmallVector<Expr *> InstantiatedQueueIdExprs;

// Instantiate devnum expr if it exists.
if (C.getDevNumExpr()) {
ExprResult Res = Self.TransformExpr(C.getDevNumExpr());
if (!Res.isUsable())
return;
Res = Self.getSema().OpenACC().ActOnIntExpr(OpenACCDirectiveKind::Invalid,
C.getClauseKind(),
C.getBeginLoc(), Res.get());
if (!Res.isUsable())
return;

DevNumExpr = Res.get();
}

// Instantiate queue ids.
for (Expr *CurQueueIdExpr : C.getQueueIdExprs()) {
ExprResult Res = Self.TransformExpr(CurQueueIdExpr);
if (!Res.isUsable())
return;
Res = Self.getSema().OpenACC().ActOnIntExpr(OpenACCDirectiveKind::Invalid,
C.getClauseKind(),
C.getBeginLoc(), Res.get());
if (!Res.isUsable())
return;

InstantiatedQueueIdExprs.push_back(Res.get());
}

ParsedClause.setWaitDetails(DevNumExpr, C.getQueuesLoc(),
std::move(InstantiatedQueueIdExprs));
}

NewClause = OpenACCWaitClause::Create(
Self.getSema().getASTContext(), ParsedClause.getBeginLoc(),
ParsedClause.getLParenLoc(), ParsedClause.getDevNumExpr(),
ParsedClause.getQueuesLoc(), ParsedClause.getQueueIdExprs(),
ParsedClause.getEndLoc());
}
} // namespace
template <typename Derived>
OpenACCClause *TreeTransform<Derived>::TransformOpenACCClause(
Expand Down
18 changes: 17 additions & 1 deletion clang/lib/Serialization/ASTReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11766,6 +11766,14 @@ SmallVector<Expr *> ASTRecordReader::readOpenACCVarList() {
return VarList;
}

SmallVector<Expr *> ASTRecordReader::readOpenACCIntExprList() {
unsigned NumExprs = readInt();
llvm::SmallVector<Expr *> ExprList;
for (unsigned I = 0; I < NumExprs; ++I)
ExprList.push_back(readSubExpr());
return ExprList;
}

OpenACCClause *ASTRecordReader::readOpenACCClause() {
OpenACCClauseKind ClauseKind = readEnum<OpenACCClauseKind>();
SourceLocation BeginLoc = readSourceLocation();
Expand Down Expand Up @@ -11888,6 +11896,15 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() {
return OpenACCAsyncClause::Create(getContext(), BeginLoc, LParenLoc,
AsyncExpr, EndLoc);
}
case OpenACCClauseKind::Wait: {
SourceLocation LParenLoc = readSourceLocation();
Expr *DevNumExpr = readBool() ? readSubExpr() : nullptr;
SourceLocation QueuesLoc = readSourceLocation();
llvm::SmallVector<Expr *> QueueIdExprs = readOpenACCIntExprList();
return OpenACCWaitClause::Create(getContext(), BeginLoc, LParenLoc,
DevNumExpr, QueuesLoc, QueueIdExprs,
EndLoc);
}

case OpenACCClauseKind::Finalize:
case OpenACCClauseKind::IfPresent:
Expand All @@ -11913,7 +11930,6 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() {
case OpenACCClauseKind::DType:
case OpenACCClauseKind::Tile:
case OpenACCClauseKind::Gang:
case OpenACCClauseKind::Wait:
case OpenACCClauseKind::Invalid:
llvm_unreachable("Clause serialization not yet implemented");
}
Expand Down
20 changes: 18 additions & 2 deletions clang/lib/Serialization/ASTWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7791,6 +7791,12 @@ void ASTRecordWriter::writeOpenACCVarList(const OpenACCClauseWithVarList *C) {
AddStmt(E);
}

void ASTRecordWriter::writeOpenACCIntExprList(ArrayRef<Expr *> Exprs) {
writeUInt32(Exprs.size());
for (Expr *E : Exprs)
AddStmt(E);
}

void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) {
writeEnum(C->getClauseKind());
writeSourceLocation(C->getBeginLoc());
Expand All @@ -7810,7 +7816,7 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) {
return;
}
case OpenACCClauseKind::Self: {
const auto *SC = cast<OpenACCIfClause>(C);
const auto *SC = cast<OpenACCSelfClause>(C);
writeSourceLocation(SC->getLParenLoc());
writeBool(SC->hasConditionExpr());
if (SC->hasConditionExpr())
Expand Down Expand Up @@ -7916,6 +7922,17 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) {
AddStmt(const_cast<Expr *>(AC->getIntExpr()));
return;
}
case OpenACCClauseKind::Wait: {
const auto *WC = cast<OpenACCWaitClause>(C);
writeSourceLocation(WC->getLParenLoc());
writeBool(WC->getDevNumExpr());
if (const Expr *DNE = WC->getDevNumExpr())
AddStmt(const_cast<Expr *>(DNE));
writeSourceLocation(WC->getQueuesLoc());

writeOpenACCIntExprList(WC->getQueueIdExprs());
return;
}

case OpenACCClauseKind::Finalize:
case OpenACCClauseKind::IfPresent:
Expand All @@ -7941,7 +7958,6 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) {
case OpenACCClauseKind::DType:
case OpenACCClauseKind::Tile:
case OpenACCClauseKind::Gang:
case OpenACCClauseKind::Wait:
case OpenACCClauseKind::Invalid:
llvm_unreachable("Clause serialization not yet implemented");
}
Expand Down
26 changes: 13 additions & 13 deletions clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,13 @@ class MIGChecker : public Checker<check::PostCall, check::PreStmt<ReturnStmt>,
// additionally an argument of a MIG routine, the checker keeps track of that
// information and issues a warning when an error is returned from the
// respective routine.
std::vector<std::pair<CallDescription, unsigned>> Deallocators = {
CallDescriptionMap<unsigned> Deallocators = {
#define CALL(required_args, deallocated_arg, ...) \
{{{__VA_ARGS__}, required_args}, deallocated_arg}
// E.g., if the checker sees a C function 'vm_deallocate' that is
// defined on class 'IOUserClient' that has exactly 3 parameters, it knows
// that argument #1 (starting from 0, i.e. the second argument) is going
// to be consumed in the sense of the MIG consume-on-success convention.
{{CDM::SimpleFunc, {__VA_ARGS__}, required_args}, deallocated_arg}
// E.g., if the checker sees a C function 'vm_deallocate' that has
// exactly 3 parameters, it knows that argument #1 (starting from 0, i.e.
// the second argument) is going to be consumed in the sense of the MIG
// consume-on-success convention.
CALL(3, 1, "vm_deallocate"),
CALL(3, 1, "mach_vm_deallocate"),
CALL(2, 0, "mig_deallocate"),
Expand All @@ -78,6 +78,9 @@ class MIGChecker : public Checker<check::PostCall, check::PreStmt<ReturnStmt>,
CALL(1, 0, "thread_inspect_deallocate"),
CALL(1, 0, "upl_deallocate"),
CALL(1, 0, "vm_map_deallocate"),
#undef CALL
#define CALL(required_args, deallocated_arg, ...) \
{{CDM::CXXMethod, {__VA_ARGS__}, required_args}, deallocated_arg}
// E.g., if the checker sees a method 'releaseAsyncReference64()' that is
// defined on class 'IOUserClient' that takes exactly 1 argument, it knows
// that the argument is going to be consumed in the sense of the MIG
Expand All @@ -87,7 +90,7 @@ class MIGChecker : public Checker<check::PostCall, check::PreStmt<ReturnStmt>,
#undef CALL
};

CallDescription OsRefRetain{{"os_ref_retain"}, 1};
CallDescription OsRefRetain{CDM::SimpleFunc, {"os_ref_retain"}, 1};

void checkReturnAux(const ReturnStmt *RS, CheckerContext &C) const;

Expand Down Expand Up @@ -198,15 +201,12 @@ void MIGChecker::checkPostCall(const CallEvent &Call, CheckerContext &C) const {
if (!isInMIGCall(C))
return;

auto I = llvm::find_if(Deallocators,
[&](const std::pair<CallDescription, unsigned> &Item) {
return Item.first.matches(Call);
});
if (I == Deallocators.end())
const unsigned *ArgIdxPtr = Deallocators.lookup(Call);
if (!ArgIdxPtr)
return;

ProgramStateRef State = C.getState();
unsigned ArgIdx = I->second;
unsigned ArgIdx = *ArgIdxPtr;
SVal Arg = Call.getArgSVal(ArgIdx);
const ParmVarDecl *PVD = getOriginParam(Arg, C);
if (!PVD || State->contains<RefCountedParameters>(PVD))
Expand Down
19 changes: 15 additions & 4 deletions clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3451,7 +3451,7 @@ static bool isReferenceCountingPointerDestructor(const CXXDestructorDecl *DD) {
if (N.contains_insensitive("ptr") || N.contains_insensitive("pointer")) {
if (N.contains_insensitive("ref") || N.contains_insensitive("cnt") ||
N.contains_insensitive("intrusive") ||
N.contains_insensitive("shared")) {
N.contains_insensitive("shared") || N.ends_with_insensitive("rc")) {
return true;
}
}
Expand Down Expand Up @@ -3483,13 +3483,24 @@ PathDiagnosticPieceRef MallocBugVisitor::VisitNode(const ExplodedNode *N,
// original reference count is positive, we should not report use-after-frees
// on objects deleted in such destructors. This can probably be improved
// through better shared pointer modeling.
if (ReleaseDestructorLC) {
if (ReleaseDestructorLC && (ReleaseDestructorLC == CurrentLC ||
ReleaseDestructorLC->isParentOf(CurrentLC))) {
if (const auto *AE = dyn_cast<AtomicExpr>(S)) {
// Check for manual use of atomic builtins.
AtomicExpr::AtomicOp Op = AE->getOp();
if (Op == AtomicExpr::AO__c11_atomic_fetch_add ||
Op == AtomicExpr::AO__c11_atomic_fetch_sub) {
if (ReleaseDestructorLC == CurrentLC ||
ReleaseDestructorLC->isParentOf(CurrentLC)) {
BR.markInvalid(getTag(), S);
}
} else if (const auto *CE = dyn_cast<CallExpr>(S)) {
// Check for `std::atomic` and such. This covers both regular method calls
// and operator calls.
if (const auto *MD =
dyn_cast_or_null<CXXMethodDecl>(CE->getDirectCallee())) {
const CXXRecordDecl *RD = MD->getParent();
// A bit wobbly with ".contains()" because it may be like
// "__atomic_base" or something.
if (StringRef(RD->getNameAsString()).contains("atomic")) {
BR.markInvalid(getTag(), S);
}
}
Expand Down
23 changes: 15 additions & 8 deletions clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@

namespace clang {

std::pair<const Expr *, bool>
tryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj) {
bool tryToFindPtrOrigin(
const Expr *E, bool StopAtFirstRefCountedObj,
std::function<bool(const clang::Expr *, bool)> callback) {
while (E) {
if (auto *tempExpr = dyn_cast<MaterializeTemporaryExpr>(E)) {
E = tempExpr->getSubExpr();
Expand All @@ -31,12 +32,18 @@ tryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj) {
E = tempExpr->getSubExpr();
continue;
}
if (auto *Expr = dyn_cast<ConditionalOperator>(E)) {
return tryToFindPtrOrigin(Expr->getTrueExpr(), StopAtFirstRefCountedObj,
callback) &&
tryToFindPtrOrigin(Expr->getFalseExpr(), StopAtFirstRefCountedObj,
callback);
}
if (auto *cast = dyn_cast<CastExpr>(E)) {
if (StopAtFirstRefCountedObj) {
if (auto *ConversionFunc =
dyn_cast_or_null<FunctionDecl>(cast->getConversionFunction())) {
if (isCtorOfRefCounted(ConversionFunc))
return {E, true};
return callback(E, true);
}
}
// FIXME: This can give false "origin" that would lead to false negatives
Expand All @@ -51,7 +58,7 @@ tryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj) {
if (IsGetterOfRefCt && *IsGetterOfRefCt) {
E = memberCall->getImplicitObjectArgument();
if (StopAtFirstRefCountedObj) {
return {E, true};
return callback(E, true);
}
continue;
}
Expand All @@ -68,17 +75,17 @@ tryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj) {
if (auto *callee = call->getDirectCallee()) {
if (isCtorOfRefCounted(callee)) {
if (StopAtFirstRefCountedObj)
return {E, true};
return callback(E, true);

E = call->getArg(0);
continue;
}

if (isReturnValueRefCounted(callee))
return {E, true};
return callback(E, true);

if (isSingleton(callee))
return {E, true};
return callback(E, true);

if (isPtrConversion(callee)) {
E = call->getArg(0);
Expand All @@ -95,7 +102,7 @@ tryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj) {
break;
}
// Some other expression.
return {E, false};
return callback(E, false);
}

bool isASafeCallArg(const Expr *E) {
Expand Down
11 changes: 7 additions & 4 deletions clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "llvm/ADT/APInt.h"
#include "llvm/Support/Casting.h"

#include <functional>
#include <string>
#include <utility>

Expand Down Expand Up @@ -48,10 +49,12 @@ class Expr;
/// represents ref-counted object during the traversal we return relevant
/// sub-expression and true.
///
/// \returns subexpression that we traversed to and if \p
/// StopAtFirstRefCountedObj is true we also return whether we stopped early.
std::pair<const clang::Expr *, bool>
tryToFindPtrOrigin(const clang::Expr *E, bool StopAtFirstRefCountedObj);
/// Calls \p callback with the subexpression that we traversed to and if \p
/// StopAtFirstRefCountedObj is true we also specify whether we stopped early.
/// Returns false if any of calls to callbacks returned false. Otherwise true.
bool tryToFindPtrOrigin(
const clang::Expr *E, bool StopAtFirstRefCountedObj,
std::function<bool(const clang::Expr *, bool)> callback);

/// For \p E referring to a ref-countable/-counted pointer/reference we return
/// whether it's a safe call argument. Examples: function parameter or
Expand Down
29 changes: 13 additions & 16 deletions clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -309,21 +309,8 @@ class TrivialFunctionAnalysisVisitor
bool VisitDefaultStmt(const DefaultStmt *DS) { return VisitChildren(DS); }

bool VisitUnaryOperator(const UnaryOperator *UO) {
// Operator '*' and '!' are allowed as long as the operand is trivial.
auto op = UO->getOpcode();
if (op == UO_Deref || op == UO_AddrOf || op == UO_LNot || op == UO_Not)
return Visit(UO->getSubExpr());

if (UO->isIncrementOp() || UO->isDecrementOp()) {
// Allow increment or decrement of a POD type.
if (auto *RefExpr = dyn_cast<DeclRefExpr>(UO->getSubExpr())) {
if (auto *Decl = dyn_cast<VarDecl>(RefExpr->getDecl()))
return Decl->isLocalVarDeclOrParm() &&
Decl->getType().isPODType(Decl->getASTContext());
}
}
// Other operators are non-trivial.
return false;
// Unary operators are trivial if its operand is trivial except co_await.
return UO->getOpcode() != UO_Coawait && Visit(UO->getSubExpr());
}

bool VisitBinaryOperator(const BinaryOperator *BO) {
Expand Down Expand Up @@ -364,7 +351,7 @@ class TrivialFunctionAnalysisVisitor

if (Name == "WTFCrashWithInfo" || Name == "WTFBreakpointTrap" ||
Name == "WTFReportAssertionFailure" ||
Name == "compilerFenceForCrash" || Name == "__builtin_unreachable")
Name == "compilerFenceForCrash" || Name.find("__builtin") == 0)
return true;

return TrivialFunctionAnalysis::isTrivialImpl(Callee, Cache);
Expand Down Expand Up @@ -405,6 +392,16 @@ class TrivialFunctionAnalysisVisitor
return TrivialFunctionAnalysis::isTrivialImpl(Callee, Cache);
}

bool VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *OCE) {
if (!checkArguments(OCE))
return false;
auto *Callee = OCE->getCalleeDecl();
if (!Callee)
return false;
// Recursively descend into the callee to confirm that it's trivial as well.
return TrivialFunctionAnalysis::isTrivialImpl(Callee, Cache);
}

bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) {
if (auto *Expr = E->getExpr()) {
if (!Visit(Expr))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,25 +126,23 @@ class UncountedCallArgsChecker
}

bool isPtrOriginSafe(const Expr *Arg) const {
std::pair<const clang::Expr *, bool> ArgOrigin =
tryToFindPtrOrigin(Arg, true);

// Temporary ref-counted object created as part of the call argument
// would outlive the call.
if (ArgOrigin.second)
return true;

if (isa<CXXNullPtrLiteralExpr>(ArgOrigin.first)) {
// foo(nullptr)
return true;
}
if (isa<IntegerLiteral>(ArgOrigin.first)) {
// FIXME: Check the value.
// foo(NULL)
return true;
}

return isASafeCallArg(ArgOrigin.first);
return tryToFindPtrOrigin(Arg, /*StopAtFirstRefCountedObj=*/true,
[](const clang::Expr *ArgOrigin, bool IsSafe) {
if (IsSafe)
return true;
if (isa<CXXNullPtrLiteralExpr>(ArgOrigin)) {
// foo(nullptr)
return true;
}
if (isa<IntegerLiteral>(ArgOrigin)) {
// FIXME: Check the value.
// foo(NULL)
return true;
}
if (isASafeCallArg(ArgOrigin))
return true;
return false;
});
}

bool shouldSkipCall(const CallExpr *CE) const {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,39 +188,50 @@ class UncountedLocalVarsChecker
if (!InitExpr)
return; // FIXME: later on we might warn on uninitialized vars too

const clang::Expr *const InitArgOrigin =
tryToFindPtrOrigin(InitExpr, /*StopAtFirstRefCountedObj=*/false)
.first;
if (!InitArgOrigin)
if (tryToFindPtrOrigin(
InitExpr, /*StopAtFirstRefCountedObj=*/false,
[&](const clang::Expr *InitArgOrigin, bool IsSafe) {
if (!InitArgOrigin)
return true;

if (isa<CXXThisExpr>(InitArgOrigin))
return true;

if (isa<CXXNullPtrLiteralExpr>(InitArgOrigin))
return true;

if (isa<IntegerLiteral>(InitArgOrigin))
return true;

if (auto *Ref = llvm::dyn_cast<DeclRefExpr>(InitArgOrigin)) {
if (auto *MaybeGuardian =
dyn_cast_or_null<VarDecl>(Ref->getFoundDecl())) {
const auto *MaybeGuardianArgType =
MaybeGuardian->getType().getTypePtr();
if (MaybeGuardianArgType) {
const CXXRecordDecl *const MaybeGuardianArgCXXRecord =
MaybeGuardianArgType->getAsCXXRecordDecl();
if (MaybeGuardianArgCXXRecord) {
if (MaybeGuardian->isLocalVarDecl() &&
(isRefCounted(MaybeGuardianArgCXXRecord) ||
isRefcountedStringsHack(MaybeGuardian)) &&
isGuardedScopeEmbeddedInGuardianScope(
V, MaybeGuardian))
return true;
}
}

// Parameters are guaranteed to be safe for the duration of
// the call by another checker.
if (isa<ParmVarDecl>(MaybeGuardian))
return true;
}
}

return false;
}))
return;

if (isa<CXXThisExpr>(InitArgOrigin))
return;

if (auto *Ref = llvm::dyn_cast<DeclRefExpr>(InitArgOrigin)) {
if (auto *MaybeGuardian =
dyn_cast_or_null<VarDecl>(Ref->getFoundDecl())) {
const auto *MaybeGuardianArgType =
MaybeGuardian->getType().getTypePtr();
if (MaybeGuardianArgType) {
const CXXRecordDecl *const MaybeGuardianArgCXXRecord =
MaybeGuardianArgType->getAsCXXRecordDecl();
if (MaybeGuardianArgCXXRecord) {
if (MaybeGuardian->isLocalVarDecl() &&
(isRefCounted(MaybeGuardianArgCXXRecord) ||
isRefcountedStringsHack(MaybeGuardian)) &&
isGuardedScopeEmbeddedInGuardianScope(V, MaybeGuardian))
return;
}
}

// Parameters are guaranteed to be safe for the duration of the call
// by another checker.
if (isa<ParmVarDecl>(MaybeGuardian))
return;
}
}

reportBug(V);
}
}
Expand Down
100 changes: 100 additions & 0 deletions clang/test/AST/HLSL/packoffset.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// RUN: %clang_cc1 -triple dxil-unknown-shadermodel6.3-library -S -finclude-default-header -fnative-half-type -ast-dump -x hlsl %s | FileCheck %s


// CHECK: HLSLBufferDecl {{.*}} cbuffer A
cbuffer A
{
// CHECK-NEXT: VarDecl {{.*}} A1 'float4'
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 0 0
float4 A1 : packoffset(c);
// CHECK-NEXT: VarDecl {{.*}} col:11 A2 'float'
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 1 0
float A2 : packoffset(c1);
// CHECK-NEXT: VarDecl {{.*}} col:11 A3 'float'
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 1 1
float A3 : packoffset(c1.y);
}

// CHECK: HLSLBufferDecl {{.*}} cbuffer B
cbuffer B
{
// CHECK: VarDecl {{.*}} B0 'float'
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 0 1
float B0 : packoffset(c0.g);
// CHECK-NEXT: VarDecl {{.*}} B1 'double'
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 0 2
double B1 : packoffset(c0.b);
// CHECK-NEXT: VarDecl {{.*}} B2 'half'
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 0 0
half B2 : packoffset(c0.r);
}

// CHECK: HLSLBufferDecl {{.*}} cbuffer C
cbuffer C
{
// CHECK: VarDecl {{.*}} C0 'float'
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 1
float C0 : packoffset(c0.y);
// CHECK-NEXT: VarDecl {{.*}} C1 'float2'
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 2
float2 C1 : packoffset(c0.z);
// CHECK-NEXT: VarDecl {{.*}} C2 'half'
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 0
half C2 : packoffset(c0.x);
}


// CHECK: HLSLBufferDecl {{.*}} cbuffer D
cbuffer D
{
// CHECK: VarDecl {{.*}} D0 'float'
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 0 1
float D0 : packoffset(c0.y);
// CHECK-NEXT: VarDecl {{.*}} D1 'float[2]'
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 1 0
float D1[2] : packoffset(c1.x);
// CHECK-NEXT: VarDecl {{.*}} D2 'half3'
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 2 1
half3 D2 : packoffset(c2.y);
// CHECK-NEXT: VarDecl {{.*}} D3 'double'
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 0 2
double D3 : packoffset(c0.z);
}

struct ST {
float a;
float2 b;
half c;
};

// CHECK: HLSLBufferDecl {{.*}} cbuffer S
cbuffer S {
// CHECK: VarDecl {{.*}} S0 'float'
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 0 1
float S0 : packoffset(c0.y);
// CHECK: VarDecl {{.*}} S1 'ST'
// CHECK: HLSLPackOffsetAttr {{.*}} 1 0
ST S1 : packoffset(c1);
// CHECK: VarDecl {{.*}} S2 'double2'
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 2 0
double2 S2 : packoffset(c2);
}

struct ST2 {
float s0;
ST s1;
half s2;
};

// CHECK: HLSLBufferDecl {{.*}} cbuffer S2
cbuffer S2 {
// CHECK: VarDecl {{.*}} S20 'float'
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 0 3
float S20 : packoffset(c0.a);
// CHECK: VarDecl {{.*}} S21 'ST2'
// CHECK: HLSLPackOffsetAttr {{.*}} 1 0
ST2 S21 : packoffset(c1);
// CHECK: VarDecl {{.*}} S22 'half'
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 3 1
half S22 : packoffset(c3.y);
}
24 changes: 24 additions & 0 deletions clang/test/AST/ast-print-openacc-compute-construct.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,5 +83,29 @@ void foo() {
// CHECK: #pragma acc kernels async
#pragma acc kernels async
while(true);

// CHECK: #pragma acc parallel wait
#pragma acc parallel wait
while(true);

// CHECK: #pragma acc parallel wait()
#pragma acc parallel wait()
while(true);

// CHECK: #pragma acc parallel wait(*iPtr, i)
#pragma acc parallel wait(*iPtr, i)
while(true);

// CHECK: #pragma acc parallel wait(queues: *iPtr, i)
#pragma acc parallel wait(queues:*iPtr, i)
while(true);

// CHECK: #pragma acc parallel wait(devnum: i : *iPtr, i)
#pragma acc parallel wait(devnum:i:*iPtr, i)
while(true);

// CHECK: #pragma acc parallel wait(devnum: i : queues: *iPtr, i)
#pragma acc parallel wait(devnum:i:queues:*iPtr, i)
while(true);
}

14 changes: 14 additions & 0 deletions clang/test/Analysis/Checkers/WebKit/call-args.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -344,3 +344,17 @@ namespace cxx_member_operator_call {
// expected-warning@-1{{Call argument for parameter 'bad' is uncounted and unsafe}}
}
}

namespace call_with_ptr_on_ref {
Ref<RefCountable> provideProtected();
void bar(RefCountable* bad);
bool baz();
void foo(bool v) {
bar(v ? nullptr : provideProtected().ptr());
bar(baz() ? provideProtected().ptr() : nullptr);
bar(v ? provide() : provideProtected().ptr());
// expected-warning@-1{{Call argument for parameter 'bad' is uncounted and unsafe}}
bar(v ? provideProtected().ptr() : provide());
// expected-warning@-1{{Call argument for parameter 'bad' is uncounted and unsafe}}
}
}
Loading