10 changes: 9 additions & 1 deletion clang/lib/Sema/SemaAPINotes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -913,7 +913,15 @@ void Sema::ProcessAPINotes(Decl *D) {

// Tags
if (auto Tag = dyn_cast<TagDecl>(D)) {
std::string LookupName = Tag->getName().str();
// Determine the name of the entity to search for. If this is an
// anonymous tag that gets its linked name from a typedef, look for the
// typedef name. This allows tag-specific information to be added
// to the declaration.
std::string LookupName;
if (auto typedefName = Tag->getTypedefNameForAnonDecl())
LookupName = typedefName->getName().str();
else
LookupName = Tag->getName().str();

// Use the source location to discern if this Tag is an OPTIONS macro.
// For now we would like to limit this trick of looking up the APINote tag
Expand Down
14 changes: 11 additions & 3 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4974,6 +4974,9 @@ void Sema::setTagNameForLinkagePurposes(TagDecl *TagFromDeclSpec,

// Otherwise, set this as the anon-decl typedef for the tag.
TagFromDeclSpec->setTypedefNameForAnonDecl(NewTD);

// Now that we have a name for the tag, process API notes again.
ProcessAPINotes(TagFromDeclSpec);
}

static unsigned GetDiagnosticTypeSpecifierID(const DeclSpec &DS) {
Expand Down Expand Up @@ -9086,9 +9089,14 @@ static NamedDecl *DiagnoseInvalidRedeclaration(
SemaRef.Diag(NewFD->getLocation(), DiagMsg)
<< Name << NewDC << IsDefinition << NewFD->getLocation();

bool NewFDisConst = false;
if (CXXMethodDecl *NewMD = dyn_cast<CXXMethodDecl>(NewFD))
NewFDisConst = NewMD->isConst();
CXXMethodDecl *NewMD = dyn_cast<CXXMethodDecl>(NewFD);
if (NewMD && DiagMsg == diag::err_member_decl_does_not_match) {
CXXRecordDecl *RD = NewMD->getParent();
SemaRef.Diag(RD->getLocation(), diag::note_defined_here)
<< RD->getName() << RD->getLocation();
}

bool NewFDisConst = NewMD && NewMD->isConst();

for (SmallVectorImpl<std::pair<FunctionDecl *, unsigned> >::iterator
NearMatch = NearMatches.begin(), NearMatchEnd = NearMatches.end();
Expand Down
166 changes: 161 additions & 5 deletions clang/lib/Sema/SemaOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1073,19 +1073,68 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitCollapseClause(

SemaOpenACC::SemaOpenACC(Sema &S) : SemaBase(S) {}

SemaOpenACC::AssociatedStmtRAII::AssociatedStmtRAII(SemaOpenACC &S,
OpenACCDirectiveKind DK)
SemaOpenACC::AssociatedStmtRAII::AssociatedStmtRAII(
SemaOpenACC &S, OpenACCDirectiveKind DK,
ArrayRef<const OpenACCClause *> UnInstClauses,
ArrayRef<OpenACCClause *> Clauses)
: SemaRef(S), WasInsideComputeConstruct(S.InsideComputeConstruct),
DirKind(DK) {
DirKind(DK), LoopRAII(SemaRef, /*PreserveDepth=*/false) {
// Compute constructs end up taking their 'loop'.
if (DirKind == OpenACCDirectiveKind::Parallel ||
DirKind == OpenACCDirectiveKind::Serial ||
DirKind == OpenACCDirectiveKind::Kernels) {
SemaRef.InsideComputeConstruct = true;
SemaRef.ParentlessLoopConstructs.swap(ParentlessLoopConstructs);
} else if (DirKind == OpenACCDirectiveKind::Loop) {
SetCollapseInfoBeforeAssociatedStmt(UnInstClauses, Clauses);
}
}

void SemaOpenACC::AssociatedStmtRAII::SetCollapseInfoBeforeAssociatedStmt(
ArrayRef<const OpenACCClause *> UnInstClauses,
ArrayRef<OpenACCClause *> Clauses) {

// Reset this checking for loops that aren't covered in a RAII object.
SemaRef.CollapseInfo.CurLevelHasLoopAlready = false;
SemaRef.CollapseInfo.CollapseDepthSatisfied = true;

// We make sure to take an optional list of uninstantiated clauses, so that
// we can check to make sure we don't 'double diagnose' in the event that
// the value of 'N' was not dependent in a template. We also ensure during
// Sema that there is only 1 collapse on each construct, so we can count on
// the fact that if both find a 'collapse', that they are the same one.
auto *CollapseClauseItr =
llvm::find_if(Clauses, llvm::IsaPred<OpenACCCollapseClause>);
auto *UnInstCollapseClauseItr =
llvm::find_if(UnInstClauses, llvm::IsaPred<OpenACCCollapseClause>);

if (Clauses.end() == CollapseClauseItr)
return;

OpenACCCollapseClause *CollapseClause =
cast<OpenACCCollapseClause>(*CollapseClauseItr);

SemaRef.CollapseInfo.ActiveCollapse = CollapseClause;
Expr *LoopCount = CollapseClause->getLoopCount();

// If the loop count is still instantiation dependent, setting the depth
// counter isn't necessary, so return here.
if (!LoopCount || LoopCount->isInstantiationDependent())
return;

// Suppress diagnostics if we've done a 'transform' where the previous version
// wasn't dependent, meaning we already diagnosed it.
if (UnInstCollapseClauseItr != UnInstClauses.end() &&
!cast<OpenACCCollapseClause>(*UnInstCollapseClauseItr)
->getLoopCount()
->isInstantiationDependent())
return;

SemaRef.CollapseInfo.CollapseDepthSatisfied = false;
SemaRef.CollapseInfo.CurCollapseCount =
cast<ConstantExpr>(LoopCount)->getResultAsAPSInt();
}

SemaOpenACC::AssociatedStmtRAII::~AssociatedStmtRAII() {
SemaRef.InsideComputeConstruct = WasInsideComputeConstruct;
if (DirKind == OpenACCDirectiveKind::Parallel ||
Expand All @@ -1094,6 +1143,9 @@ SemaOpenACC::AssociatedStmtRAII::~AssociatedStmtRAII() {
assert(SemaRef.ParentlessLoopConstructs.empty() &&
"Didn't consume loop construct list?");
SemaRef.ParentlessLoopConstructs.swap(ParentlessLoopConstructs);
} else if (DirKind == OpenACCDirectiveKind::Loop) {
// Nothing really to do here, the LoopInConstruct should handle restorations
// correctly.
}
}

Expand Down Expand Up @@ -1646,10 +1698,103 @@ ExprResult SemaOpenACC::CheckCollapseLoopCount(Expr *LoopCount) {
ConstantExpr::Create(getASTContext(), LoopCount, APValue{*ICE})};
}

void SemaOpenACC::ActOnWhileStmt(SourceLocation WhileLoc) {
if (!getLangOpts().OpenACC)
return;

if (!CollapseInfo.TopLevelLoopSeen)
return;

if (CollapseInfo.CurCollapseCount && *CollapseInfo.CurCollapseCount > 0) {
Diag(WhileLoc, diag::err_acc_invalid_in_collapse_loop) << /*while loop*/ 1;
assert(CollapseInfo.ActiveCollapse && "Collapse count without object?");
Diag(CollapseInfo.ActiveCollapse->getBeginLoc(),
diag::note_acc_collapse_clause_here);

// Remove the value so that we don't get cascading errors in the body. The
// caller RAII object will restore this.
CollapseInfo.CurCollapseCount = std::nullopt;
}
}

void SemaOpenACC::ActOnDoStmt(SourceLocation DoLoc) {
if (!getLangOpts().OpenACC)
return;

if (!CollapseInfo.TopLevelLoopSeen)
return;

if (CollapseInfo.CurCollapseCount && *CollapseInfo.CurCollapseCount > 0) {
Diag(DoLoc, diag::err_acc_invalid_in_collapse_loop) << /*do loop*/ 2;
assert(CollapseInfo.ActiveCollapse && "Collapse count without object?");
Diag(CollapseInfo.ActiveCollapse->getBeginLoc(),
diag::note_acc_collapse_clause_here);

// Remove the value so that we don't get cascading errors in the body. The
// caller RAII object will restore this.
CollapseInfo.CurCollapseCount = std::nullopt;
}
}

void SemaOpenACC::ActOnForStmtBegin(SourceLocation ForLoc) {
if (!getLangOpts().OpenACC)
return;

// Enable the while/do-while checking.
CollapseInfo.TopLevelLoopSeen = true;

if (CollapseInfo.CurCollapseCount && *CollapseInfo.CurCollapseCount > 0) {

// OpenACC 3.3 2.9.1:
// Each associated loop, except the innermost, must contain exactly one loop
// or loop nest.
// This checks for more than 1 loop at the current level, the
// 'depth'-satisifed checking manages the 'not zero' case.
if (CollapseInfo.CurLevelHasLoopAlready) {
Diag(ForLoc, diag::err_acc_collapse_multiple_loops);
assert(CollapseInfo.ActiveCollapse && "No collapse object?");
Diag(CollapseInfo.ActiveCollapse->getBeginLoc(),
diag::note_acc_collapse_clause_here);
} else {
--(*CollapseInfo.CurCollapseCount);

// Once we've hit zero here, we know we have deep enough 'for' loops to
// get to the bottom.
if (*CollapseInfo.CurCollapseCount == 0)
CollapseInfo.CollapseDepthSatisfied = true;
}
}

// Set this to 'false' for the body of this loop, so that the next level
// checks independently.
CollapseInfo.CurLevelHasLoopAlready = false;
}

void SemaOpenACC::ActOnForStmtEnd(SourceLocation ForLoc, StmtResult Body) {
if (!getLangOpts().OpenACC)
return;
// Set this to 'true' so if we find another one at this level we can diagnose.
CollapseInfo.CurLevelHasLoopAlready = true;
}

bool SemaOpenACC::ActOnStartStmtDirective(OpenACCDirectiveKind K,
SourceLocation StartLoc) {
SemaRef.DiscardCleanupsInEvaluationContext();
SemaRef.PopExpressionEvaluationContext();

// OpenACC 3.3 2.9.1:
// Intervening code must not contain other OpenACC directives or calls to API
// routines.
//
// ALL constructs are ill-formed if there is an active 'collapse'
if (CollapseInfo.CurCollapseCount && *CollapseInfo.CurCollapseCount > 0) {
Diag(StartLoc, diag::err_acc_invalid_in_collapse_loop)
<< /*OpenACC Construct*/ 0 << K;
assert(CollapseInfo.ActiveCollapse && "Collapse count without object?");
Diag(CollapseInfo.ActiveCollapse->getBeginLoc(),
diag::note_acc_collapse_clause_here);
}

return diagnoseConstructAppertainment(*this, K, StartLoc, /*IsStmt=*/true);
}

Expand Down Expand Up @@ -1713,12 +1858,23 @@ StmtResult SemaOpenACC::ActOnAssociatedStmt(SourceLocation DirectiveLoc,
// the 'structured block'.
return AssocStmt;
case OpenACCDirectiveKind::Loop:
if (AssocStmt.isUsable() &&
!isa<CXXForRangeStmt, ForStmt>(AssocStmt.get())) {
if (!AssocStmt.isUsable())
return StmtError();

if (!isa<CXXForRangeStmt, ForStmt>(AssocStmt.get())) {
Diag(AssocStmt.get()->getBeginLoc(), diag::err_acc_loop_not_for_loop);
Diag(DirectiveLoc, diag::note_acc_construct_here) << K;
return StmtError();
}

if (!CollapseInfo.CollapseDepthSatisfied) {
Diag(DirectiveLoc, diag::err_acc_collapse_insufficient_loops);
assert(CollapseInfo.ActiveCollapse && "Collapse count without object?");
Diag(CollapseInfo.ActiveCollapse->getBeginLoc(),
diag::note_acc_collapse_clause_here);
return StmtError();
}

// TODO OpenACC: 2.9 ~ line 2010 specifies that the associated loop has some
// restrictions when there is a 'seq' clause in place. We probably need to
// implement that, including piping in the clauses here.
Expand Down
34 changes: 30 additions & 4 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -8200,6 +8200,11 @@ TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) {
if (Cond.isInvalid())
return StmtError();

// OpenACC Restricts a while-loop inside of certain construct/clause
// combinations, so diagnose that here in OpenACC mode.
SemaOpenACC::LoopInConstructRAII LCR{SemaRef.OpenACC()};
SemaRef.OpenACC().ActOnWhileStmt(S->getBeginLoc());

// Transform the body
StmtResult Body = getDerived().TransformStmt(S->getBody());
if (Body.isInvalid())
Expand All @@ -8217,6 +8222,11 @@ TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) {
template<typename Derived>
StmtResult
TreeTransform<Derived>::TransformDoStmt(DoStmt *S) {
// OpenACC Restricts a do-loop inside of certain construct/clause
// combinations, so diagnose that here in OpenACC mode.
SemaOpenACC::LoopInConstructRAII LCR{SemaRef.OpenACC()};
SemaRef.OpenACC().ActOnDoStmt(S->getBeginLoc());

// Transform the body
StmtResult Body = getDerived().TransformStmt(S->getBody());
if (Body.isInvalid())
Expand Down Expand Up @@ -8270,11 +8280,18 @@ TreeTransform<Derived>::TransformForStmt(ForStmt *S) {
if (S->getInc() && !FullInc.get())
return StmtError();

// OpenACC Restricts a for-loop inside of certain construct/clause
// combinations, so diagnose that here in OpenACC mode.
SemaOpenACC::LoopInConstructRAII LCR{SemaRef.OpenACC()};
SemaRef.OpenACC().ActOnForStmtBegin(S->getBeginLoc());

// Transform the body
StmtResult Body = getDerived().TransformStmt(S->getBody());
if (Body.isInvalid())
return StmtError();

SemaRef.OpenACC().ActOnForStmtEnd(S->getBeginLoc(), Body);

if (!getDerived().AlwaysRebuild() &&
Init.get() == S->getInit() &&
Cond.get() == std::make_pair(S->getConditionVariable(), S->getCond()) &&
Expand Down Expand Up @@ -9008,10 +9025,17 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) {
}
}

// OpenACC Restricts a while-loop inside of certain construct/clause
// combinations, so diagnose that here in OpenACC mode.
SemaOpenACC::LoopInConstructRAII LCR{SemaRef.OpenACC()};
SemaRef.OpenACC().ActOnForStmtBegin(S->getBeginLoc());

StmtResult Body = getDerived().TransformStmt(S->getBody());
if (Body.isInvalid())
return StmtError();

SemaRef.OpenACC().ActOnForStmtEnd(S->getBeginLoc(), Body);

// Body has changed but we didn't rebuild the for-range statement. Rebuild
// it now so we have a new statement to attach the body to.
if (Body.get() != S->getBody() && NewStmt.get() == S) {
Expand Down Expand Up @@ -11894,8 +11918,9 @@ StmtResult TreeTransform<Derived>::TransformOpenACCComputeConstruct(
return StmtError();

// Transform Structured Block.
SemaOpenACC::AssociatedStmtRAII AssocStmtRAII(getSema().OpenACC(),
C->getDirectiveKind());
SemaOpenACC::AssociatedStmtRAII AssocStmtRAII(
getSema().OpenACC(), C->getDirectiveKind(), C->clauses(),
TransformedClauses);
StmtResult StrBlock = getDerived().TransformStmt(C->getStructuredBlock());
StrBlock = getSema().OpenACC().ActOnAssociatedStmt(
C->getBeginLoc(), C->getDirectiveKind(), StrBlock);
Expand All @@ -11920,8 +11945,9 @@ TreeTransform<Derived>::TransformOpenACCLoopConstruct(OpenACCLoopConstruct *C) {
return StmtError();

// Transform Loop.
SemaOpenACC::AssociatedStmtRAII AssocStmtRAII(getSema().OpenACC(),
C->getDirectiveKind());
SemaOpenACC::AssociatedStmtRAII AssocStmtRAII(
getSema().OpenACC(), C->getDirectiveKind(), C->clauses(),
TransformedClauses);
StmtResult Loop = getDerived().TransformStmt(C->getLoop());
Loop = getSema().OpenACC().ActOnAssociatedStmt(C->getBeginLoc(),
C->getDirectiveKind(), Loop);
Expand Down
1 change: 0 additions & 1 deletion clang/lib/StaticAnalyzer/Checkers/ErrnoChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ class ErrnoChecker
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
const LocationContext *LCtx, const CallEvent *Call) const;
void checkBranchCondition(const Stmt *Condition, CheckerContext &Ctx) const;

/// Indicates if a read (load) of \c errno is allowed in a non-condition part
/// of \c if, \c switch, loop and conditional statements when the errno
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,5 @@ Tags:
SwiftName: SuccessfullyRenamedA
- Name: RenamedAgainInAPINotesB
SwiftName: SuccessfullyRenamedB
- Name: AnonEnumWithTypedefName
SwiftName: SuccessfullyRenamedC
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,7 @@ void *getCFAuditedToNone_DUMP(void);
- (id)getOwnedToUnowned __attribute__((__ns_returns_retained__));
- (id)getUnownedToOwned __attribute__((__ns_returns_not_retained__));
@end

typedef enum {
kConstantInAnonEnum
} AnonEnumWithTypedefName;
3 changes: 3 additions & 0 deletions clang/test/APINotes/types.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@

// CHECK: struct __attribute__((swift_name("SuccessfullyRenamedA"))) RenamedAgainInAPINotesA {
// CHECK: struct __attribute__((swift_name("SuccessfullyRenamedB"))) RenamedAgainInAPINotesB {
// CHECK: typedef enum __attribute__((swift_name("SuccessfullyRenamedC"))) {
// CHECK-NEXT: kConstantInAnonEnum
// CHECK-NEXT: } AnonEnumWithTypedefName

void test(OverriddenTypes *overridden) {
int *ip1 = global_int_ptr; // expected-warning{{incompatible pointer types initializing 'int *' with an expression of type 'double (*)(int, int)'}}
Expand Down
2 changes: 1 addition & 1 deletion clang/test/APINotes/yaml-roundtrip-2.test
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ REQUIRES: shell

We expect only the document markers to be emitted

CHECK: 50d
CHECK: 52d
CHECK: 1d
3 changes: 2 additions & 1 deletion clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,11 +164,12 @@ namespace {

#if __cplusplus < 201402L
namespace ImplicitConstexprDef {
struct A {
struct A { // #defined-here
void f(); // expected-note {{member declaration does not match because it is not const qualified}}
};

constexpr void A::f() { } // expected-warning {{'constexpr' non-static member function will not be implicitly 'const' in C++14; add 'const' to avoid a change in behavior}}
// expected-error@-1 {{out-of-line definition of 'f' does not match any declaration in 'ImplicitConstexprDef::A'}}
// expected-note@#defined-here {{defined here}}
}
#endif
3 changes: 2 additions & 1 deletion clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p8.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s

struct A { };
struct A { }; // #defined-here
A::A (enum { e1 }) {} // expected-error{{cannot be defined in a parameter}}
void A::f(enum { e2 }) {} // expected-error{{cannot be defined in a parameter}}

enum { e3 } A::g() { } // expected-error{{cannot be defined in the result type}} \
// expected-error{{out-of-line definition}}
// expected-note@#defined-here{{defined here}}
3 changes: 2 additions & 1 deletion clang/test/CXX/dcl/dcl.fct/p17.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ namespace unconstrained {
// expected-error@-1{{no matching}}

template<typename T>
struct S {
struct S { // #defined-here
constexpr auto f1(auto x, T t) -> decltype(x + t);

template<typename U>
Expand All @@ -110,6 +110,7 @@ namespace unconstrained {
template<typename U>
constexpr auto S<T>::f2(auto x, U u, T t) -> decltype(x + u + t) { return x + u + t; }
// expected-error@-1 {{out-of-line definition of 'f2' does not match any declaration in 'S<T>'}}
// expected-note@#defined-here {{S defined here}}

template<typename T>
template<typename U>
Expand Down
3 changes: 2 additions & 1 deletion clang/test/CXX/drs/cwg22xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,13 @@ namespace MultilevelSpecialization {
// default argument -- how far back do we look when determining whether a
// parameter was expanded from a pack?
// -- zygoloid 2020-06-02
template<typename ...T> struct B {
template<typename ...T> struct B { // #cwg2233-B
template <T... V> void f(int i = 0, int (&... arr)[V]);
};
template<> template<int a, int b>
void B<int, int>::f(int i, int (&arr1)[a], int (&arr2)[b]) {}
// since-cxx11-error@-1 {{out-of-line definition of 'f' does not match any declaration in 'cwg2233::MultilevelSpecialization::B<int, int>'}}
// since-cxx11-note@#cwg2233-B {{defined here}}
template<> template<>
void B<int, int>::f<1, 1>(int i, int (&arr1a)[1], int (&arr2a)[1]) {}
}
Expand Down
64 changes: 32 additions & 32 deletions clang/test/CXX/drs/cwg27xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -pedantic-errors -verify=expected %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++14 -pedantic-errors -verify=expected %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -pedantic-errors -verify=expected %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 -pedantic-errors -verify=expected %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++23 -pedantic-errors -verify=expected,since-cxx23 %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++2c -pedantic-errors -verify=expected,since-cxx23,since-cxx26 %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 -pedantic-errors -verify=expected,since-cxx20 %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++23 -pedantic-errors -verify=expected,since-cxx20,since-cxx23 %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++2c -pedantic-errors -verify=expected,since-cxx20,since-cxx23,since-cxx26 %s

#if __cplusplus == 199711L
#define static_assert(...) __extension__ _Static_assert(__VA_ARGS__)
Expand All @@ -29,6 +29,35 @@ namespace std {
#endif
} // namespace std

namespace cwg2707 { // cwg2707: 20

#if __cplusplus >= 202002L

template <class T, unsigned N> struct A { // #cwg2707-A
T value[N];
};

template <typename... T>
A(T...) -> A<int, sizeof...(T)> requires (sizeof...(T) == 2); // #cwg2707-guide-A

// Brace elision is not allowed for synthesized CTAD guides if the array size
// is value-dependent.
// So this should pick up our explicit deduction guide.
A a = {1, 2};

A b = {3, 4, 5};
// since-cxx20-error@-1 {{no viable constructor or deduction guide}}
// since-cxx20-note@#cwg2707-A {{candidate function template not viable}}
// since-cxx20-note@#cwg2707-A {{implicit deduction guide}}
// since-cxx20-note@#cwg2707-guide-A {{constraints not satisfied}}
// since-cxx20-note@#cwg2707-guide-A {{because 'sizeof...(T) == 2' (3 == 2) evaluated to false}}
// since-cxx20-note@#cwg2707-A {{candidate function template not viable}}
// since-cxx20-note@#cwg2707-A {{implicit deduction guide}}

#endif

} // namespace cwg2707

namespace cwg2718 { // cwg2718: 2.7
struct B {};
struct D;
Expand Down Expand Up @@ -200,32 +229,3 @@ static_assert(false, f().s);
// since-cxx26-error@-1 {{static assertion failed: Hello}}
#endif
} // namespace cwg2798

namespace cwg2707 { // cwg2707: 20

#if __cplusplus >= 202002L

template <class T, unsigned N> struct A {
T value[N];
};

template <typename... T>
A(T...) -> A<int, sizeof...(T)> requires (sizeof...(T) == 2);

// Brace elision is not allowed for synthesized CTAD guides if the array size
// is value-dependent.
// So this should pick up our explicit deduction guide.
A a = {1, 2};

A b = {3, 4, 5};
// expected-error@-1 {{no viable constructor or deduction guide}} \
// expected-note@-13 {{candidate function template not viable}} \
// expected-note@-13 {{implicit deduction guide}} \
// expected-note@-8 {{constraints not satisfied}} \
// expected-note@-8 {{because 'sizeof...(T) == 2' (3 == 2) evaluated to false}} \
// expected-note@-13 {{candidate function template not viable}} \
// expected-note@-13 {{implicit deduction guide}}

#endif

} // namespace cwg2707
13 changes: 9 additions & 4 deletions clang/test/CXX/drs/cwg3xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -597,9 +597,10 @@ namespace cwg336 { // cwg336: yes
void mf2();
};
};
template<> template<class X> class A<int>::B {};
template<> template<class X> class A<int>::B {}; // #cwg336-B
template<> template<> template<class T> void A<int>::B<double>::mf1(T t) {}
// expected-error@-1 {{out-of-line definition of 'mf1' does not match any declaration in 'cwg336::Pre::A<int>::B<double>'}}
// expected-note@#cwg336-B {{defined here}}
template<class Y> template<> void A<Y>::B<double>::mf2() {}
// expected-error@-1 {{nested name specifier 'A<Y>::B<double>::' for declaration does not refer into a class, class template or class template partial specialization}}
}
Expand Down Expand Up @@ -758,16 +759,18 @@ namespace cwg347 { // cwg347: yes
void g();
};

struct derived : base {};
struct derived : base {}; // #cwg347-derived

struct derived::nested {};
// expected-error@-1 {{no struct named 'nested' in 'cwg347::derived'}}
int derived::n;
// expected-error@-1 {{no member named 'n' in 'cwg347::derived'}}
void derived::f() {}
// expected-error@-1 {{out-of-line definition of 'f' does not match any declaration in 'cwg347::derived'}}
// expected-note@#cwg347-derived {{defined here}}
void derived::g() {}
// expected-error@-1 {{out-of-line definition of 'g' does not match any declaration in 'cwg347::derived'}}
// expected-note@#cwg347-derived {{defined here}}
}

// cwg348: na
Expand Down Expand Up @@ -1009,18 +1012,20 @@ namespace cwg355 { struct ::cwg355_S s; }
// cwg356: na

namespace cwg357 { // cwg357: yes
template<typename T> struct A {
template<typename T> struct A { // #cwg357-A
void f() const; // #cwg357-f
};
template<typename T> void A<T>::f() {}
// expected-error@-1 {{out-of-line definition of 'f' does not match any declaration in 'A<T>'}}
// expected-note@#cwg357-A {{defined here}}
// expected-note@#cwg357-f {{member declaration does not match because it is const qualified}}

struct B {
struct B { // #cwg357-B
template<typename T> void f();
};
template<typename T> void B::f() const {}
// expected-error@-1 {{out-of-line definition of 'f' does not match any declaration in 'cwg357::B'}}
// expected-note@#cwg357-B {{defined here}}
}

namespace cwg358 { // cwg358: yes
Expand Down
3 changes: 2 additions & 1 deletion clang/test/CXX/special/class.inhctor/p8.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ struct C {
template<typename T> constexpr C(T t) : v(t) {}
int v;
};
struct D : C {
struct D : C { // #defined-here
using C::C;
};
static_assert(D(123).v == 123, "");

template<typename T> constexpr D::D(T t) : C(t) {} // expected-error {{does not match any declaration in 'D'}}
// expected-note@#defined-here {{defined here}}
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,14 @@ int AA::A() { return sizeof(T); }
namespace diag {

template <unsigned N>
struct TA {
struct TA { // #defined-here
template <template <unsigned> class TT> requires TT<N>::happy
int A();
};

template <unsigned N>
template <template <unsigned> class TT> int TA<N>::A() { return sizeof(TT<N>); }
// expected-error@-1{{out-of-line definition of 'A' does not match any declaration in 'TA<N>'}}
// expected-note@#defined-here{{defined here}}

} // end namespace diag
10 changes: 5 additions & 5 deletions clang/test/CXX/temp/temp.res/temp.local/p8.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ namespace SearchClassBetweenTemplateParameterLists {

template<typename T> struct A {
using AA = void;
template<typename U> struct B {
template<typename U> struct B { // #defined-here
using BB = void;
void f(U);
void g(U);
Expand Down Expand Up @@ -127,19 +127,19 @@ namespace SearchClassBetweenTemplateParameterLists {
template<typename T> template<typename BB>
void A<T>::B<BB>::g(BB) { // expected-error {{does not match}}
BB bb; // expected-error {{incomplete type}}
}
} // expected-note@#defined-here {{defined here}}

// error, 'AA' found in (4)
template<typename AA> template<typename U>
void A<AA>::B<U>::h(AA) { // expected-error {{does not match}}
AA aa; // expected-error {{incomplete type}}
}
} // expected-note@#defined-here {{defined here}}

// error, 'BB' found in (2)
template<typename BB> template<typename U>
void A<BB>::B<U>::i(BB) { // expected-error {{does not match}}
BB bb; // expected-error {{incomplete type}}
}
} // expected-note@#defined-here {{defined here}}

// OK, 'BB' found in (1)
template<typename T> template<typename U> template<typename BB>
Expand All @@ -151,7 +151,7 @@ namespace SearchClassBetweenTemplateParameterLists {
template<typename T> template<typename BB> template<typename V>
void A<T>::B<BB>::k(V) { // expected-error {{does not match}}
BB bb; // expected-error {{incomplete type}}
}
} // expected-note@#defined-here {{defined here}}

int CC;
template <typename> struct C;
Expand Down
6 changes: 3 additions & 3 deletions clang/test/CXX/temp/temp.spec/temp.expl.spec/p12.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ constexpr void A::f1<long>(); // since-cxx14-error {{no function template matche
// members of a class template explicitly specialized for an implicitly
// instantiated specialization of that template.
template<typename T>
struct B {
struct B { // #defined-here
void g0(); // since-cxx14-note {{previous declaration is here}}
// cxx11-note@-1 {{member declaration does not match because it is not const qualified}}

Expand All @@ -49,11 +49,13 @@ template<>
constexpr void B<short>::g0(); // since-cxx14-error {{constexpr declaration of 'g0' follows non-constexpr declaration}}
// cxx11-error@-1 {{out-of-line declaration of 'g0' does not match any declaration in 'B<short>'}}
// cxx11-warning@-2 {{'constexpr' non-static member function will not be implicitly 'const' in C++14; add 'const'}}
// expected-note@#defined-here {{defined here}}

template<>
constexpr void B<short>::g1(); // since-cxx14-error {{out-of-line declaration of 'g1' does not match any declaration in 'B<short>'}}
// cxx11-error@-1 {{constexpr declaration of 'g1' follows non-constexpr declaration}}
// cxx11-warning@-2 {{'constexpr' non-static member function will not be implicitly 'const' in C++14; add 'const'}}
// expected-note@#defined-here {{defined here}}

template<>
template<typename U>
Expand All @@ -66,5 +68,3 @@ template<typename U>
constexpr void B<long>::h1(); // since-cxx14-error {{out-of-line declaration of 'h1' does not match any declaration in 'B<long>'}}
// cxx11-error@-1 {{constexpr declaration of 'h1' follows non-constexpr declaration}}
// cxx11-warning@-2 {{'constexpr' non-static member function will not be implicitly 'const' in C++14; add 'const'}}


3 changes: 2 additions & 1 deletion clang/test/CXX/temp/temp.spec/temp.expl.spec/p14-23.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace N0 {
concept D = I < 8;

template<int I>
struct A {
struct A { // #defined-here
constexpr static int f() { return 0; }
constexpr static int f() requires C<I> && D<I> { return 1; }
constexpr static int f() requires C<I> { return 2; }
Expand Down Expand Up @@ -56,6 +56,7 @@ namespace N0 {

template<>
constexpr int A<0>::h() { return 2; } // expected-error {{out-of-line definition of 'h' does not match any declaration in 'N0::A<0>'}}
// expected-note@#defined-here {{defined here}}

static_assert(A<5>::h() == 0);
static_assert(A<4>::h() == 1);
Expand Down
3 changes: 2 additions & 1 deletion clang/test/CXX/temp/temp.spec/temp.expl.spec/p18.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ template<class T1> class A {
};

template<> template<class X>
class A<long>::B { };
class A<long>::B { }; // #defined-here

template<> template<> template<class T>
void A<int>::B<double>::mf1(T t) { }

template<> template<> template<class T>
void A<long>::B<double>::mf1(T t) { } // expected-error{{does not match}}
// expected-note@#defined-here{{defined here}}

// FIXME: This diagnostic could probably be better.
template<class Y> template<>
Expand Down
81 changes: 80 additions & 1 deletion clang/test/CodeGen/X86/adc-builtins.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -ffreestanding -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -x c -ffreestanding -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -x c++ -ffreestanding -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s

#include <x86intrin.h>

Expand Down Expand Up @@ -43,3 +44,81 @@ unsigned char test_subborrow_u64(unsigned char __cf, unsigned long long __x,
// CHECK: [[CF:%.*]] = extractvalue { i8, i64 } [[SBB]], 0
return _subborrow_u64(__cf, __x, __y, __p);
}

// Test constexpr handling.
#if defined(__cplusplus) && (__cplusplus >= 201103L)

template<typename X>
struct Result {
unsigned char A;
X B;
constexpr bool operator==(const Result<X> &Other) {
return A == Other.A && B == Other.B;
}
};

constexpr Result<unsigned int>
const_test_addcarry_u32(unsigned char __cf, unsigned int __x, unsigned int __y)
{
unsigned int __r{};
return { _addcarry_u32(__cf, __x, __y, &__r), __r };
}

void constexpr adcu32() {
static_assert(const_test_addcarry_u32(0, 0x00000000, 0x00000000) == Result<unsigned int>{0, 0x00000000});
static_assert(const_test_addcarry_u32(1, 0xFFFFFFFE, 0x00000000) == Result<unsigned int>{0, 0xFFFFFFFF});
static_assert(const_test_addcarry_u32(1, 0xFFFFFFFE, 0x00000001) == Result<unsigned int>{1, 0x00000000});
static_assert(const_test_addcarry_u32(0, 0xFFFFFFFF, 0xFFFFFFFF) == Result<unsigned int>{1, 0xFFFFFFFE});
static_assert(const_test_addcarry_u32(1, 0xFFFFFFFF, 0xFFFFFFFF) == Result<unsigned int>{1, 0xFFFFFFFF});
}

constexpr Result<unsigned int>
const_test_subborrow_u32(unsigned char __cf, unsigned int __x, unsigned int __y)
{
unsigned int __r{};
return { _subborrow_u32(__cf, __x, __y, &__r), __r };
}

void constexpr sbbu32() {
static_assert(const_test_subborrow_u32(0, 0x00000000, 0x00000000) == Result<unsigned int>{0, 0x00000000});
static_assert(const_test_subborrow_u32(0, 0x00000000, 0x00000001) == Result<unsigned int>{1, 0xFFFFFFFF});
static_assert(const_test_subborrow_u32(1, 0x00000000, 0x00000001) == Result<unsigned int>{1, 0xFFFFFFFE});
static_assert(const_test_subborrow_u32(1, 0xFFFFFFFE, 0x00000000) == Result<unsigned int>{0, 0xFFFFFFFD});
static_assert(const_test_subborrow_u32(1, 0xFFFFFFFE, 0x00000001) == Result<unsigned int>{0, 0xFFFFFFFC});
static_assert(const_test_subborrow_u32(0, 0xFFFFFFFF, 0xFFFFFFFF) == Result<unsigned int>{0, 0x00000000});
static_assert(const_test_subborrow_u32(1, 0xFFFFFFFF, 0xFFFFFFFF) == Result<unsigned int>{1, 0xFFFFFFFF});
}

constexpr Result<unsigned long long>
const_test_addcarry_u64(unsigned char __cf, unsigned long long __x, unsigned long long __y)
{
unsigned long long __r{};
return { _addcarry_u64(__cf, __x, __y, &__r), __r };
}

void constexpr adcu64() {
static_assert(const_test_addcarry_u64(0, 0x0000000000000000ULL, 0x0000000000000000ULL) == Result<unsigned long long>{0, 0x0000000000000000ULL});
static_assert(const_test_addcarry_u64(1, 0xFFFFFFFFFFFFFFFEULL, 0x0000000000000000ULL) == Result<unsigned long long>{0, 0xFFFFFFFFFFFFFFFFULL});
static_assert(const_test_addcarry_u64(1, 0xFFFFFFFFFFFFFFFEULL, 0x0000000000000001ULL) == Result<unsigned long long>{1, 0x0000000000000000ULL});
static_assert(const_test_addcarry_u64(0, 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL) == Result<unsigned long long>{1, 0xFFFFFFFFFFFFFFFEULL});
static_assert(const_test_addcarry_u64(1, 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL) == Result<unsigned long long>{1, 0xFFFFFFFFFFFFFFFFULL});
}

constexpr Result<unsigned long long>
const_test_subborrow_u64(unsigned char __cf, unsigned long long __x, unsigned long long __y)
{
unsigned long long __r{};
return { _subborrow_u64(__cf, __x, __y, &__r), __r };
}

void constexpr sbbu64() {
static_assert(const_test_subborrow_u64(0, 0x0000000000000000ULL, 0x0000000000000000ULL) == Result<unsigned long long>{0, 0x0000000000000000ULL});
static_assert(const_test_subborrow_u64(0, 0x0000000000000000ULL, 0x0000000000000001ULL) == Result<unsigned long long>{1, 0xFFFFFFFFFFFFFFFFULL});
static_assert(const_test_subborrow_u64(1, 0x0000000000000000ULL, 0x0000000000000001ULL) == Result<unsigned long long>{1, 0xFFFFFFFFFFFFFFFEULL});
static_assert(const_test_subborrow_u64(1, 0xFFFFFFFFFFFFFFFEULL, 0x0000000000000000ULL) == Result<unsigned long long>{0, 0xFFFFFFFFFFFFFFFDULL});
static_assert(const_test_subborrow_u64(1, 0xFFFFFFFFFFFFFFFEULL, 0x0000000000000001ULL) == Result<unsigned long long>{0, 0xFFFFFFFFFFFFFFFCULL});
static_assert(const_test_subborrow_u64(0, 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL) == Result<unsigned long long>{0, 0x0000000000000000ULL});
static_assert(const_test_subborrow_u64(1, 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL) == Result<unsigned long long>{1, 0xFFFFFFFFFFFFFFFFULL});
}

#endif
47 changes: 46 additions & 1 deletion clang/test/CodeGen/X86/adx-builtins.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ffreestanding -target-feature +adx -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -x c -triple x86_64-unknown-unknown -ffreestanding -target-feature +adx -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -x c++ -triple x86_64-unknown-unknown -ffreestanding -target-feature +adx -emit-llvm -o - %s | FileCheck %s

#include <immintrin.h>

Expand All @@ -22,3 +23,47 @@ unsigned char test_addcarryx_u64(unsigned char __cf, unsigned long long __x,
// CHECK: [[CF:%.*]] = extractvalue { i8, i64 } [[ADC]], 0
return _addcarryx_u64(__cf, __x, __y, __p);
}

// Test constexpr handling.
#if defined(__cplusplus) && (__cplusplus >= 201103L)

template<typename X>
struct Result {
unsigned char A;
X B;
constexpr bool operator==(const Result<X> &Other) {
return A == Other.A && B == Other.B;
}
};

constexpr Result<unsigned int>
const_test_addcarryx_u32(unsigned char __cf, unsigned int __x, unsigned int __y)
{
unsigned int __r{};
return { _addcarryx_u32(__cf, __x, __y, &__r), __r };
}

void constexpr addxu32() {
static_assert(const_test_addcarryx_u32(0, 0x00000000, 0x00000000) == Result<unsigned int>{0, 0x00000000});
static_assert(const_test_addcarryx_u32(1, 0xFFFFFFFE, 0x00000000) == Result<unsigned int>{0, 0xFFFFFFFF});
static_assert(const_test_addcarryx_u32(1, 0xFFFFFFFE, 0x00000001) == Result<unsigned int>{1, 0x00000000});
static_assert(const_test_addcarryx_u32(0, 0xFFFFFFFF, 0xFFFFFFFF) == Result<unsigned int>{1, 0xFFFFFFFE});
static_assert(const_test_addcarryx_u32(1, 0xFFFFFFFF, 0xFFFFFFFF) == Result<unsigned int>{1, 0xFFFFFFFF});
}

constexpr Result<unsigned long long>
const_test_addcarryx_u64(unsigned char __cf, unsigned long long __x, unsigned long long __y)
{
unsigned long long __r{};
return { _addcarryx_u64(__cf, __x, __y, &__r), __r };
}

void constexpr addxu64() {
static_assert(const_test_addcarryx_u64(0, 0x0000000000000000ULL, 0x0000000000000000ULL) == Result<unsigned long long>{0, 0x0000000000000000ULL});
static_assert(const_test_addcarryx_u64(1, 0xFFFFFFFFFFFFFFFEULL, 0x0000000000000000ULL) == Result<unsigned long long>{0, 0xFFFFFFFFFFFFFFFFULL});
static_assert(const_test_addcarryx_u64(1, 0xFFFFFFFFFFFFFFFEULL, 0x0000000000000001ULL) == Result<unsigned long long>{1, 0x0000000000000000ULL});
static_assert(const_test_addcarryx_u64(0, 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL) == Result<unsigned long long>{1, 0xFFFFFFFFFFFFFFFEULL});
static_assert(const_test_addcarryx_u64(1, 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL) == Result<unsigned long long>{1, 0xFFFFFFFFFFFFFFFFULL});
}

#endif
2 changes: 1 addition & 1 deletion clang/test/CodeGenCXX/debug-info-alias.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ x::bar<int> bi;
// CHECK: [[BFLOAT]] = !DIDerivedType(tag: DW_TAG_typedef, name: "bar<float>"
x::bar<float> bf;
// CHECK: !DIGlobalVariable(name: "bz",{{.*}} type: [[BBAZ:![0-9]+]]
// CHECK: [[BBAZ]] = !DIDerivedType(tag: DW_TAG_typedef, name: "bar<baz<int> >"
// CHECK: [[BBAZ]] = !DIDerivedType(tag: DW_TAG_typedef, name: "bar<baz<int,{{ *}}int> >"
x::bar<baz<int>> bz;

using
Expand Down
4 changes: 4 additions & 0 deletions clang/test/CodeGenCXX/mangle-concept.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -verify -std=c++20 -emit-llvm -triple %itanium_abi_triple -o - %s -fclang-abi-compat=latest | FileCheck %s
// RUN: %clang_cc1 -verify -std=c++20 -emit-llvm -triple %itanium_abi_triple -o - %s -fclang-abi-compat=19 | FileCheck %s --check-prefix=CLANG19
// RUN: %clang_cc1 -verify -std=c++20 -emit-llvm -triple %itanium_abi_triple -o - %s -fclang-abi-compat=17 | FileCheck %s --check-prefix=CLANG17
// expected-no-diagnostics

Expand Down Expand Up @@ -59,18 +60,21 @@ namespace test2 {
// CLANG17: call {{.*}}@_ZN5test21fEz(
f(ai);
// CHECK: call {{.*}}@_ZN5test21AIiEF1gIvEEvzQaa4TrueIT_E4TrueITL0__E(
// CLANG19: call {{.*}}@_ZN5test2F1gIvEEvzQaa4TrueIT_E4TrueITL0__E(
// CLANG17: call {{.*}}@_ZN5test21gIvEEvz(
g(ai);
// CHECK: call {{.*}}@_ZN5test21hIvEEvzQ4TrueITL0__E(
// CLANG17: call {{.*}}@_ZN5test21hIvEEvz(
h(ai);
// CHECK: call {{.*}}@_ZN5test21AIiEF1iIvQaa4TrueIT_E4TrueITL0__EEEvz(
// CLANG19: call {{.*}}@_ZN5test2F1iIvQaa4TrueIT_E4TrueITL0__EEEvz(
// CLANG17: call {{.*}}@_ZN5test21iIvEEvz(
i(ai);
// CHECK: call {{.*}}@_ZN5test21jIvQ4TrueITL0__EEEvz(
// CLANG17: call {{.*}}@_ZN5test21jIvEEvz(
j(ai);
// CHECK: call {{.*}}@_ZN5test21AIiEF1kITk4TruevQ4TrueIT_EEEvz(
// CLANG19: call {{.*}}@_ZN5test2F1kITk4TruevQ4TrueIT_EEEvz(
// CLANG17: call {{.*}}@_ZN5test21kIvEEvz(
k(ai);
// CHECK: call {{.*}}@_ZN5test21lITk4TruevEEvz(
Expand Down
4 changes: 3 additions & 1 deletion clang/test/FixIt/member-mismatch.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
// RUN: %clang_cc1 -verify %s
// RUN: not %clang_cc1 -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s

class Foo {
class Foo { // #defined-here
int get() const; // expected-note {{because it is const qualified}}
void set(int); // expected-note {{because it is not const qualified}}
};

// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:15-[[@LINE+1]]:15}:" const"
int Foo::get() {} // expected-error {{does not match any declaration}}
// expected-note@#defined-here {{defined here}}
// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:20-[[@LINE+1]]:26}:""
void Foo::set(int) const {} // expected-error {{does not match any declaration}}
// expected-note@#defined-here {{defined here}}
3 changes: 2 additions & 1 deletion clang/test/Parser/cxx-class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,10 @@ class F {
#endif

namespace ctor_error {
class Foo {};
class Foo {}; // #defined-here
// By [class.qual]p2, this is a constructor declaration.
Foo::Foo (F) = F(); // expected-error{{does not match any declaration in 'ctor_error::Foo'}}
// expected-note@#defined-here{{defined here}}

class Ctor { // expected-note{{not complete until the closing '}'}}
Ctor(f)(int); // ok
Expand Down
9 changes: 5 additions & 4 deletions clang/test/SemaCXX/attr-target-mv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,14 +180,15 @@ void constexpr_test() {
static_assert(foo() == 2, "Should call 'default' in a constexpr context");
}

struct BadOutOfLine {
struct BadOutOfLine { // #defined-here
int __attribute__((target("sse4.2"))) foo(int);
int __attribute__((target("default"))) foo(int);
};

int __attribute__((target("sse4.2"))) BadOutOfLine::foo(int) { return 0; }
int __attribute__((target("default"))) BadOutOfLine::foo(int) { return 1; }
// expected-error@+3 {{out-of-line definition of 'foo' does not match any declaration in 'BadOutOfLine'}}
// expected-note@-3 {{member declaration nearly matches}}
// expected-note@-3 {{member declaration nearly matches}}
// expected-error@+4 {{out-of-line definition of 'foo' does not match any declaration in 'BadOutOfLine'}}
// expected-note@#defined-here {{defined here}}
// expected-note@-4 {{member declaration nearly matches}}
// expected-note@-4 {{member declaration nearly matches}}
int __attribute__((target("arch=atom"))) BadOutOfLine::foo(int) { return 1; }
9 changes: 5 additions & 4 deletions clang/test/SemaCXX/attr-target-version.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,14 @@ using ::Decl;
__attribute__((target_version("jscvt"))) void Decl();
} // namespace Nms

class Out {
class Out { // #defined-here
int __attribute__((target_version("bti"))) func(void);
int __attribute__((target_version("ssbs2"))) func(void);
};
int __attribute__((target_version("bti"))) Out::func(void) { return 1; }
int __attribute__((target_version("ssbs2"))) Out::func(void) { return 2; }
// expected-error@+3 {{out-of-line definition of 'func' does not match any declaration in 'Out'}}
// expected-note@-3 {{member declaration nearly matches}}
// expected-note@-3 {{member declaration nearly matches}}
// expected-error@+4 {{out-of-line definition of 'func' does not match any declaration in 'Out'}}
// expected-note@-2 {{member declaration nearly matches}}
// expected-note@-4 {{member declaration nearly matches}}
// expected-note@#defined-here {{defined here}}
int __attribute__((target_version("rng"))) Out::func(void) { return 3; }
2 changes: 1 addition & 1 deletion clang/test/SemaCXX/enable_if.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ int surrogate(int);
struct Incomplete; // expected-note{{forward declaration of 'Incomplete'}} \
// expected-note {{forward declaration of 'Incomplete'}}

struct X {
struct X { // expected-note{{defined here}}
X() = default; // expected-note{{candidate constructor not viable: requires 0 arguments, but 1 was provided}}
X(const X&) = default; // expected-note{{candidate constructor not viable: no known conversion from 'bool' to 'const X' for 1st argument}}
X(bool b) __attribute__((enable_if(b, "chosen when 'b' is true"))); // expected-note{{candidate disabled: chosen when 'b' is true}}
Expand Down
14 changes: 8 additions & 6 deletions clang/test/SemaCXX/function-redecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ void B::Notypocorrection(int) { // expected-error {{out-of-line definition of 'N
}

struct X { int f(); };
struct Y : public X {};
struct Y : public X {}; // expected-note {{defined here}}
int Y::f() { return 3; } // expected-error {{out-of-line definition of 'f' does not match any declaration in 'Y'}}

namespace test1 {
Expand All @@ -70,7 +70,7 @@ struct Foo {
};
}

class Bar {
class Bar { // expected-note {{defined here}}
void f(test1::Foo::Inner foo) const; // expected-note {{member declaration does not match because it is const qualified}}
};

Expand All @@ -80,7 +80,8 @@ void Bar::f(Foo::Inner foo) { // expected-error {{out-of-line definition of 'f'
(void)foo;
}

class Crash {
class Crash { // expected-note {{defined here}}
// expected-note@-1 {{defined here}}
public:
void GetCart(int count) const;
};
Expand All @@ -89,7 +90,8 @@ void Crash::cart(int count) const {} // expected-error {{out-of-line definition
// ...while this one crashed clang
void Crash::chart(int count) const {} // expected-error {{out-of-line definition of 'chart' does not match any declaration in 'Crash'}}

class TestConst {
class TestConst { // expected-note {{defined here}}
// expected-note@-1 {{defined here}}
public:
int getit() const; // expected-note {{member declaration does not match because it is const qualified}}
void setit(int); // expected-note {{member declaration does not match because it is not const qualified}}
Expand All @@ -102,7 +104,7 @@ int TestConst::getit() { // expected-error {{out-of-line definition of 'getit' d
void TestConst::setit(int) const { // expected-error {{out-of-line definition of 'setit' does not match any declaration in 'TestConst'}}
}

struct J { int typo() const; };
struct J { int typo() const; }; // expected-note {{defined here}}
int J::typo_() { return 3; } // expected-error {{out-of-line definition of 'typo_' does not match any declaration in 'J'}}

// Ensure we correct the redecl of Foo::isGood to Bar::Foo::isGood and not
Expand All @@ -126,7 +128,7 @@ bool Foo::isGood() { // expected-error {{out-of-line definition of 'isGood' does
void Foo::beEvil() {} // expected-error {{out-of-line definition of 'beEvil' does not match any declaration in namespace 'redecl_typo::Foo'; did you mean 'BeEvil'?}}
}

struct CVQualFun {
struct CVQualFun { // expected-note {{defined here}}
void func(int a, int &b); // expected-note {{type of 2nd parameter of member declaration does not match definition ('int &' vs 'int')}}
};

Expand Down
6 changes: 4 additions & 2 deletions clang/test/SemaCXX/lambda-unevaluated.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,21 +70,23 @@ void use_g() { g<6>(&"hello"); } // expected-error {{ambiguous}}
namespace GH51416 {

template <class T>
struct A {
struct A { // #defined-here-A
void spam(decltype([] {}));
};

template <class T>
void A<T>::spam(decltype([] {})) // expected-error{{out-of-line definition of 'spam' does not match}}
// expected-note@#defined-here-A{{defined here}}
{}

struct B {
struct B { // #defined-here-B
template <class T>
void spam(decltype([] {}));
};

template <class T>
void B::spam(decltype([] {})) {} // expected-error{{out-of-line definition of 'spam' does not match}}
// expected-note@#defined-here-B{{defined here}}

} // namespace GH51416

Expand Down
10 changes: 7 additions & 3 deletions clang/test/SemaCXX/nested-name-spec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ int A::C::cx = 17;

static int A::C::cx2 = 17; // expected-error{{'static' can}}

class C2 {
class C2 { // #defined-here-C2
void m(); // expected-note{{member declaration does not match because it is not const qualified}}

void f(const int& parm); // expected-note{{type of 1st parameter of member declaration does not match definition ('const int &' vs 'int')}}
Expand All @@ -36,8 +36,10 @@ class C2 {
};

void C2::m() const { } // expected-error{{out-of-line definition of 'm' does not match any declaration in 'C2'}}
// expected-note@#defined-here-C2{{defined here}}

void C2::f(int) { } // expected-error{{out-of-line definition of 'f' does not match any declaration in 'C2'}}
// expected-note@#defined-here-C2{{defined here}}

void C2::m() {
x = 0;
Expand Down Expand Up @@ -122,12 +124,13 @@ namespace E {
}


class Operators {
class Operators { // #defined-here-Operators
Operators operator+(const Operators&) const; // expected-note{{member declaration does not match because it is const qualified}}
operator bool();
};

Operators Operators::operator+(const Operators&) { // expected-error{{out-of-line definition of 'operator+' does not match any declaration in 'Operators'}}
// expected-note@#defined-here-Operators{{defined here}}
Operators ops;
return ops;
}
Expand All @@ -149,9 +152,10 @@ void A::f() {} // expected-error-re{{out-of-line definition of 'f' does not matc

void A::g(const int&) { } // expected-error{{out-of-line definition of 'g' does not match any declaration in namespace 'A'}}

struct Struct { };
struct Struct { }; // #defined-here-Struct

void Struct::f() { } // expected-error{{out-of-line definition of 'f' does not match any declaration in 'Struct'}}
// expected-note@#defined-here-Struct{{defined here}}

void global_func(int);
void global_func2(int);
Expand Down
6 changes: 5 additions & 1 deletion clang/test/SemaCXX/out-of-line-def-mismatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ namespace N2 {
namespace N1 {
class C1 {};

struct S2 {
struct S2 { // expected-note {{defined here}}
// expected-note@-1 {{defined here}}
// expected-note@-2 {{defined here}}
// expected-note@-3 {{defined here}}
// expected-note@-4 {{defined here}}
void func(S1*); // expected-note {{type of 1st parameter of member declaration does not match definition ('S1 *' (aka 'N2::S1 *') vs 'S1 *' (aka 'N2::N1::S1 *'))}}
void func(C1&, unsigned, const S1*); // expected-note {{type of 3rd parameter of member declaration does not match definition ('const S1 *' (aka 'const N2::S1 *') vs 'const S1 *' (aka 'const N2::N1::S1 *'))}}
void func(const S1*, unsigned); //expected-note {{type of 1st parameter of member declaration does not match definition ('const S1 *' vs 'S1')}}
Expand Down
1 change: 1 addition & 0 deletions clang/test/SemaCXX/typo-correction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ class Parent {
};
class Child: public Parent {};
void Child::add_types(int value) {} // expected-error{{out-of-line definition of 'add_types' does not match any declaration in 'Child'}}
// expected-note@-2{{defined here}}

// Fix the callback based filtering of typo corrections within
// Sema::ActOnIdExpression by Parser::ParseCastExpression to allow type names as
Expand Down
221 changes: 221 additions & 0 deletions clang/test/SemaOpenACC/loop-construct-collapse-clause.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,224 @@ void negative_constexpr(int i) {
negative_constexpr_templ<int, 1>(); // #NCET1
}

template<unsigned Val>
void depth_too_high_templ() {
// expected-error@+2{{'collapse' clause specifies a loop count greater than the number of available loops}}
// expected-note@+1{{active 'collapse' clause defined here}}
#pragma acc loop collapse(Val)
for(;;)
for(;;);
}

void depth_too_high() {
depth_too_high_templ<3>(); // expected-note{{in instantiation of function template specialization}}

// expected-error@+2{{'collapse' clause specifies a loop count greater than the number of available loops}}
// expected-note@+1{{active 'collapse' clause defined here}}
#pragma acc loop collapse(3)
for(;;)
for(;;);

// expected-error@+2{{'collapse' clause specifies a loop count greater than the number of available loops}}
// expected-note@+1{{active 'collapse' clause defined here}}
#pragma acc loop collapse(three())
for(;;)
for(;;);

// expected-error@+2{{'collapse' clause specifies a loop count greater than the number of available loops}}
// expected-note@+1{{active 'collapse' clause defined here}}
#pragma acc loop collapse(ConvertsThree{})
for(;;)
for(;;);
}

template<typename T, unsigned Three>
void not_single_loop_templ() {
T Arr[5];
// expected-error@+2{{'collapse' clause specifies a loop count greater than the number of available loops}}
// expected-note@+1 2{{active 'collapse' clause defined here}}
#pragma acc loop collapse(3)
for(auto x : Arr) {
for(auto y : Arr){
do{}while(true); // expected-error{{do loop cannot appear in intervening code of a 'loop' with a 'collapse' clause}}
}
}

// expected-error@+2{{'collapse' clause specifies a loop count greater than the number of available loops}}
// expected-note@+1 2{{active 'collapse' clause defined here}}
#pragma acc loop collapse(Three)
for(;;) {
for(;;){
do{}while(true); // expected-error{{do loop cannot appear in intervening code of a 'loop' with a 'collapse' clause}}
}
}

#pragma acc loop collapse(Three)
for(;;) {
for(;;){
for(;;){
do{}while(true);
}
}
}
// expected-error@+2{{'collapse' clause specifies a loop count greater than the number of available loops}}
// expected-note@+1 2{{active 'collapse' clause defined here}}
#pragma acc loop collapse(Three)
for(auto x : Arr) {
for(auto y: Arr) {
do{}while(true); // expected-error{{do loop cannot appear in intervening code of a 'loop' with a 'collapse' clause}}
}
}

#pragma acc loop collapse(Three)
for(auto x : Arr) {
for(auto y: Arr) {
for(auto z: Arr) {
do{}while(true);
}
}
}
}

void not_single_loop() {
not_single_loop_templ<int, 3>(); // expected-note{{in instantiation of function template}}

// expected-note@+1{{active 'collapse' clause defined here}}
#pragma acc loop collapse(3)
for(;;) {
for(;;){
for(;;);
}
while(true); // expected-error{{while loop cannot appear in intervening code of a 'loop' with a 'collapse' clause}}
}

// expected-note@+1{{active 'collapse' clause defined here}}
#pragma acc loop collapse(3)
for(;;) {
for(;;){
for(;;);
}
do{}while(true); // expected-error{{do loop cannot appear in intervening code of a 'loop' with a 'collapse' clause}}
}

// expected-error@+2{{'collapse' clause specifies a loop count greater than the number of available loops}}
// expected-note@+1 2{{active 'collapse' clause defined here}}
#pragma acc loop collapse(3)
for(;;) {
for(;;){
while(true); // expected-error{{while loop cannot appear in intervening code of a 'loop' with a 'collapse' clause}}
}
}
// expected-error@+2{{'collapse' clause specifies a loop count greater than the number of available loops}}
// expected-note@+1 2{{active 'collapse' clause defined here}}
#pragma acc loop collapse(3)
for(;;) {
for(;;){
do{}while(true); // expected-error{{do loop cannot appear in intervening code of a 'loop' with a 'collapse' clause}}
}
}

#pragma acc loop collapse(2)
for(;;) {
for(;;){
do{}while(true);
}
}
#pragma acc loop collapse(2)
for(;;) {
for(;;){
while(true);
}
}

int Arr[5];
// expected-error@+2{{'collapse' clause specifies a loop count greater than the number of available loops}}
// expected-note@+1 2{{active 'collapse' clause defined here}}
#pragma acc loop collapse(3)
for(auto x : Arr) {
for(auto y : Arr){
do{}while(true); // expected-error{{do loop cannot appear in intervening code of a 'loop' with a 'collapse' clause}}
}
}

// expected-note@+1 {{active 'collapse' clause defined here}}
#pragma acc loop collapse(3)
for (;;) {
for (;;) {
for(;;);
}
// expected-error@+1{{more than one for-loop in a loop associated with OpenACC 'loop' construct with a 'collapse' clause}}
for(;;);
}

// expected-note@+1 {{active 'collapse' clause defined here}}
#pragma acc loop collapse(3)
for (;;) {
for (;;) {
for(;;);
// expected-error@+1{{more than one for-loop in a loop associated with OpenACC 'loop' construct with a 'collapse' clause}}
for(;;);
}
}

for(;;);
#pragma acc loop collapse(3)
for (;;) {
for (;;) {
for (;;);
}
}
}

template<unsigned Two, unsigned Three>
void no_other_directives() {
#pragma acc loop collapse(Two)
for(;;) {
for (;;) { // last loop associated with the top level.
// expected-error@+1{{'collapse' clause specifies a loop count greater than the number of available loops}}
#pragma acc loop collapse(Three) // expected-note 2{{active 'collapse' clause defined here}}
for(;;) {
for(;;) {
// expected-error@+1{{OpenACC 'serial' construct cannot appear in intervening code of a 'loop' with a 'collapse' clause}}
#pragma acc serial
;
}
}
}
}
#pragma acc loop collapse(Two)// expected-note{{active 'collapse' clause defined here}}
for(;;) {
for (;;) { // last loop associated with the top level.
#pragma acc loop collapse(Three)
for(;;) {
for(;;) {
for(;;);
}
}
}
// expected-error@+1{{OpenACC 'serial' construct cannot appear in intervening code of a 'loop' with a 'collapse' clause}}
#pragma acc serial
;
}
}

void no_other_directives() {
no_other_directives<2,3>(); // expected-note{{in instantiation of function template specialization}}

// Ok, not inside the intervening list
#pragma acc loop collapse(2)
for(;;) {
for(;;) {
#pragma acc data // expected-warning{{OpenACC construct 'data' not yet implemented}}
}
}
// expected-note@+1{{active 'collapse' clause defined here}}
#pragma acc loop collapse(2)
for(;;) {
// expected-error@+1{{OpenACC 'data' construct cannot appear in intervening code of a 'loop' with a 'collapse' clause}}
#pragma acc data // expected-warning{{OpenACC construct 'data' not yet implemented}}
for(;;) {
}
}
}

6 changes: 4 additions & 2 deletions clang/test/SemaTemplate/concepts-out-of-line-def.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -516,22 +516,24 @@ concept something_interesting = requires {
};

template <class T>
struct X {
struct X { // #defined-here
void foo() requires requires { requires is_not_same_v<T, int>; };
void bar(decltype(requires { requires is_not_same_v<T, int>; }));
};

template <class T>
void X<T>::foo() requires requires { requires something_interesting<T>; } {}
// expected-error@-1{{definition of 'foo' does not match any declaration}}
// expected-note@*{{}}
// expected-note@#defined-here{{defined here}}
// expected-note@-8{{member declaration nearly matches}}

template <class T>
void X<T>::foo() requires requires { requires is_not_same_v<T, int>; } {} // ok

template <class T>
void X<T>::bar(decltype(requires { requires something_interesting<T>; })) {}
// expected-error@-1{{definition of 'bar' does not match any declaration}}
// expected-note@#defined-here{{defined here}}

template <class T>
void X<T>::bar(decltype(requires { requires is_not_same_v<T, int>; })) {}
Expand Down
7 changes: 4 additions & 3 deletions clang/test/SemaTemplate/recovery-crash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ namespace PR16225 {
namespace test1 {
template <typename> class ArraySlice {};
class Foo;
class NonTemplateClass {
class NonTemplateClass { // #defined-here
void MemberFunction(ArraySlice<Foo>, int);
template <class T> void MemberFuncTemplate(ArraySlice<T>, int);
};
Expand All @@ -61,7 +61,8 @@ namespace test1 {
// expected-error@+1 {{member 'UndeclaredMethod' used before its declaration}}
UndeclaredMethod(resource_data);
}
// expected-error@+2 {{out-of-line definition of 'UndeclaredMethod' does not match any declaration}}
// expected-note@+1 {{member is declared here}}
// expected-error@+3 {{out-of-line definition of 'UndeclaredMethod' does not match any declaration}}
// expected-note@+2 {{member is declared here}}
// expected-note@#defined-here {{defined here}}
void NonTemplateClass::UndeclaredMethod() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2873,6 +2873,40 @@ TEST_P(UncheckedOptionalAccessTest, OptionalValueStruct) {
)");
}

// FIXME: A case that we should handle but currently don't.
// When there is a field of type reference to non-optional, we may
// stop recursively creating storage locations.
// E.g., the field `second` below in `pair` should eventually lead to
// the optional `x` in `A`.
TEST_P(UncheckedOptionalAccessTest, NestedOptionalThroughNonOptionalRefField) {
ExpectDiagnosticsFor(R"(
#include "unchecked_optional_access_test.h"

struct A {
$ns::$optional<int> x;
};

struct pair {
int first;
const A &second;
};

struct B {
$ns::$optional<pair>& nonConstGetRef();
};

void target(B b) {
const auto& maybe_pair = b.nonConstGetRef();
if (!maybe_pair.has_value())
return;

if(!maybe_pair->second.x.has_value())
return;
maybe_pair->second.x.value(); // [[unsafe]]
}
)");
}

TEST_P(UncheckedOptionalAccessTest, OptionalValueInitialization) {
ExpectDiagnosticsFor(
R"(
Expand Down
16 changes: 7 additions & 9 deletions clang/utils/TableGen/ClangAttrEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1529,9 +1529,8 @@ createArgument(const Record &Arg, StringRef Attr,

if (!Ptr) {
// Search in reverse order so that the most-derived type is handled first.
ArrayRef<std::pair<Record*, SMRange>> Bases = Search->getSuperClasses();
for (const auto &Base : reverse(Bases)) {
if ((Ptr = createArgument(Arg, Attr, Base.first)))
for (const auto &[Base, _] : reverse(Search->getSuperClasses())) {
if ((Ptr = createArgument(Arg, Attr, Base)))
break;
}
}
Expand Down Expand Up @@ -2744,12 +2743,11 @@ static void emitAttributes(const RecordKeeper &Records, raw_ostream &OS,
if (!R.getValueAsBit("ASTNode"))
continue;

ArrayRef<std::pair<Record *, SMRange>> Supers = R.getSuperClasses();
ArrayRef<std::pair<const Record *, SMRange>> Supers = R.getSuperClasses();
assert(!Supers.empty() && "Forgot to specify a superclass for the attr");
std::string SuperName;
bool Inheritable = false;
for (const auto &Super : reverse(Supers)) {
const Record *R = Super.first;
for (const auto &[R, _] : reverse(Supers)) {
if (R->getName() != "TargetSpecificAttr" &&
R->getName() != "DeclOrTypeAttr" && SuperName.empty())
SuperName = std::string(R->getName());
Expand Down Expand Up @@ -3434,7 +3432,7 @@ namespace {
}

private:
AttrClass *findClassByRecord(Record *R) const {
AttrClass *findClassByRecord(const Record *R) const {
for (auto &Class : Classes) {
if (Class->TheRecord == R)
return Class.get();
Expand Down Expand Up @@ -4739,8 +4737,8 @@ void EmitClangAttrParsedAttrImpl(const RecordKeeper &Records, raw_ostream &OS) {
if (Arg->getValueAsBitOrUnset("Fake", UnusedUnset))
continue;
ArgNames.push_back(Arg->getValueAsString("Name").str());
for (const auto &Class : Arg->getSuperClasses()) {
if (Class.first->getName().starts_with("Variadic")) {
for (const auto &[Class, _] : Arg->getSuperClasses()) {
if (Class->getName().starts_with("Variadic")) {
ArgNames.back().append("...");
break;
}
Expand Down
2 changes: 1 addition & 1 deletion clang/utils/TableGen/ClangOptionDocEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ const unsigned UnlimitedArgs = unsigned(-1);

// Get the number of arguments expected for an option, or -1 if any number of
// arguments are accepted.
unsigned getNumArgsForKind(Record *OptionKind, const Record *Option) {
unsigned getNumArgsForKind(const Record *OptionKind, const Record *Option) {
return StringSwitch<unsigned>(OptionKind->getName())
.Cases("KIND_JOINED", "KIND_JOINED_OR_SEPARATE", "KIND_SEPARATE", 1)
.Cases("KIND_REMAINING_ARGS", "KIND_REMAINING_ARGS_JOINED",
Expand Down
19 changes: 0 additions & 19 deletions compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
Original file line number Diff line number Diff line change
Expand Up @@ -10350,24 +10350,6 @@ INTERCEPTOR(SSIZE_T, pwritev2, int fd, __sanitizer_iovec *iov, int iovcnt,
#define INIT_PWRITEV2
#endif

#if SANITIZER_INTERCEPT_FREADLINK
INTERCEPTOR(SSIZE_T, freadlink, int fd, char *buf, SIZE_T bufsiz) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, freadlink, fd, buf, bufsiz);
COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
SSIZE_T res = REAL(freadlink)(fd, buf, bufsiz);
if (res > 0)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, res);
if (res >= 0 && fd > 0)
COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
return res;
}

# define INIT_FREADLINK COMMON_INTERCEPT_FUNCTION(freadlink)
#else
# define INIT_FREADLINK
#endif

#include "sanitizer_common_interceptors_netbsd_compat.inc"

namespace __sanitizer {
Expand Down Expand Up @@ -10689,7 +10671,6 @@ static void InitializeCommonInterceptors() {
INIT_CPUSET_GETAFFINITY;
INIT_PREADV2;
INIT_PWRITEV2;
INIT_FREADLINK;

INIT___PRINTF_CHK;
}
Original file line number Diff line number Diff line change
Expand Up @@ -607,13 +607,6 @@
// FIXME: also available from musl 1.2.5
#define SANITIZER_INTERCEPT_PREADV2 (SI_LINUX && __GLIBC_PREREQ(2, 26))
#define SANITIZER_INTERCEPT_PWRITEV2 (SI_LINUX && __GLIBC_PREREQ(2, 26))
#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && \
__MAC_OS_X_VERSION_MIN_REQUIRED >= 130000
# define SI_MAC_OS_DEPLOYMENT_MIN_13_00 1
#else
# define SI_MAC_OS_DEPLOYMENT_MIN_13_00 0
#endif
#define SANITIZER_INTERCEPT_FREADLINK (SI_MAC && SI_MAC_OS_DEPLOYMENT_MIN_13_00)

// This macro gives a way for downstream users to override the above
// interceptor macros irrespective of the platform they are on. They have
Expand Down
2 changes: 0 additions & 2 deletions compiler-rt/lib/scudo/standalone/combined.h
Original file line number Diff line number Diff line change
Expand Up @@ -785,8 +785,6 @@ class Allocator {
// A corrupted chunk will not be reported as owned, which is WAI.
bool isOwned(const void *Ptr) {
initThreadMaybe();
// If the allocation is not owned, the tags could be wrong.
ScopedDisableMemoryTagChecks x;
#ifdef GWP_ASAN_HOOKS
if (GuardedAlloc.pointerIsMine(Ptr))
return true;
Expand Down
133 changes: 94 additions & 39 deletions compiler-rt/lib/scudo/standalone/primary64.h
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,11 @@ template <typename Config> class SizeClassAllocator64 {
uptr BytesInFreeListAtLastCheckpoint;
uptr RangesReleased;
uptr LastReleasedBytes;
// The minimum size of pushed blocks to trigger page release.
uptr TryReleaseThreshold;
// The number of bytes not triggering `releaseToOSMaybe()` because of
// the length of release interval.
uptr PendingPushedBytesDelta;
u64 LastReleaseAtNs;
};

Expand Down Expand Up @@ -560,8 +565,6 @@ template <typename Config> class SizeClassAllocator64 {
u32 RandState GUARDED_BY(MMLock) = 0;
BlocksInfo FreeListInfo GUARDED_BY(FLLock);
PagesInfo MemMapInfo GUARDED_BY(MMLock);
// The minimum size of pushed blocks to trigger page release.
uptr TryReleaseThreshold GUARDED_BY(MMLock) = 0;
ReleaseToOsInfo ReleaseInfo GUARDED_BY(MMLock) = {};
bool Exhausted GUARDED_BY(MMLock) = false;
bool isPopulatingFreeList GUARDED_BY(FLLock) = false;
Expand Down Expand Up @@ -610,9 +613,8 @@ template <typename Config> class SizeClassAllocator64 {
return BlockSize < PageSize / 16U;
}

ALWAYS_INLINE static bool isLargeBlock(uptr BlockSize) {
const uptr PageSize = getPageSizeCached();
return BlockSize > PageSize;
ALWAYS_INLINE uptr getMinReleaseAttemptSize(uptr BlockSize) {
return roundUp(BlockSize, getPageSizeCached());
}

ALWAYS_INLINE void initRegion(RegionInfo *Region, uptr ClassId,
Expand All @@ -631,12 +633,16 @@ template <typename Config> class SizeClassAllocator64 {
(getRandomModN(&Region->RandState, 16) + 1) * PageSize;
}

const uptr BlockSize = getSizeByClassId(ClassId);
// Releasing small blocks is expensive, set a higher threshold to avoid
// frequent page releases.
if (isSmallBlock(getSizeByClassId(ClassId)))
Region->TryReleaseThreshold = PageSize * SmallerBlockReleasePageDelta;
else
Region->TryReleaseThreshold = PageSize;
if (isSmallBlock(BlockSize)) {
Region->ReleaseInfo.TryReleaseThreshold =
PageSize * SmallerBlockReleasePageDelta;
} else {
Region->ReleaseInfo.TryReleaseThreshold =
getMinReleaseAttemptSize(BlockSize);
}
}

void pushBatchClassBlocks(RegionInfo *Region, CompactPtrT *Array, u32 Size)
Expand Down Expand Up @@ -1245,6 +1251,7 @@ template <typename Config> class SizeClassAllocator64 {
uptr BytesInFreeList;
const uptr AllocatedUserEnd =
Region->MemMapInfo.AllocatedUser + Region->RegionBeg;
uptr RegionPushedBytesDelta = 0;
SinglyLinkedList<BatchGroupT> GroupsToRelease;

{
Expand All @@ -1267,6 +1274,12 @@ template <typename Config> class SizeClassAllocator64 {
return 0;
}

// Given that we will unlock the freelist for block operations, cache the
// value here so that when we are adapting the `TryReleaseThreshold`
// later, we are using the right metric.
RegionPushedBytesDelta =
BytesInFreeList - Region->ReleaseInfo.BytesInFreeListAtLastCheckpoint;

// ==================================================================== //
// 2. Determine which groups can release the pages. Use a heuristic to
// gather groups that are candidates for doing a release.
Expand Down Expand Up @@ -1310,12 +1323,45 @@ template <typename Config> class SizeClassAllocator64 {
auto SkipRegion = [](UNUSED uptr RegionIndex) { return false; };
releaseFreeMemoryToOS(Context, Recorder, SkipRegion);
if (Recorder.getReleasedRangesCount() > 0) {
// This is the case that we didn't hit the release threshold but it has
// been past a certain period of time. Thus we try to release some pages
// and if it does release some additional pages, it's hint that we are
// able to lower the threshold. Currently, this case happens when the
// `RegionPushedBytesDelta` is over half of the `TryReleaseThreshold`. As
// a result, we shrink the threshold to half accordingly.
// TODO(chiahungduan): Apply the same adjustment strategy to small blocks.
if (!isSmallBlock(BlockSize)) {
if (RegionPushedBytesDelta < Region->ReleaseInfo.TryReleaseThreshold &&
Recorder.getReleasedBytes() >
Region->ReleaseInfo.LastReleasedBytes +
getMinReleaseAttemptSize(BlockSize)) {
Region->ReleaseInfo.TryReleaseThreshold =
Max(Region->ReleaseInfo.TryReleaseThreshold / 2,
getMinReleaseAttemptSize(BlockSize));
}
}

Region->ReleaseInfo.BytesInFreeListAtLastCheckpoint = BytesInFreeList;
Region->ReleaseInfo.RangesReleased += Recorder.getReleasedRangesCount();
Region->ReleaseInfo.LastReleasedBytes = Recorder.getReleasedBytes();
}
Region->ReleaseInfo.LastReleaseAtNs = getMonotonicTimeFast();

if (Region->ReleaseInfo.PendingPushedBytesDelta > 0) {
// Instead of increasing the threshold by the amount of
// `PendingPushedBytesDelta`, we only increase half of the amount so that
// it won't be a leap (which may lead to higher memory pressure) because
// of certain memory usage bursts which don't happen frequently.
Region->ReleaseInfo.TryReleaseThreshold +=
Region->ReleaseInfo.PendingPushedBytesDelta / 2;
// This is another guard of avoiding the growth of threshold indefinitely.
// Note that we may consider to make this configurable if we have a better
// way to model this.
Region->ReleaseInfo.TryReleaseThreshold = Min<uptr>(
Region->ReleaseInfo.TryReleaseThreshold, (1UL << GroupSizeLog) / 2);
Region->ReleaseInfo.PendingPushedBytesDelta = 0;
}

// ====================================================================== //
// 5. Merge the `GroupsToRelease` back to the freelist.
// ====================================================================== //
Expand All @@ -1329,8 +1375,6 @@ template <typename Config> class SizeClassAllocator64 {
REQUIRES(Region->MMLock, Region->FLLock) {
DCHECK_GE(Region->FreeListInfo.PoppedBlocks,
Region->FreeListInfo.PushedBlocks);
const uptr PageSize = getPageSizeCached();

// Always update `BytesInFreeListAtLastCheckpoint` with the smallest value
// so that we won't underestimate the releasable pages. For example, the
// following is the region usage,
Expand All @@ -1354,34 +1398,45 @@ template <typename Config> class SizeClassAllocator64 {

const uptr RegionPushedBytesDelta =
BytesInFreeList - Region->ReleaseInfo.BytesInFreeListAtLastCheckpoint;
if (RegionPushedBytesDelta < PageSize)
return false;

// Releasing smaller blocks is expensive, so we want to make sure that a
// significant amount of bytes are free, and that there has been a good
// amount of batches pushed to the freelist before attempting to release.
if (isSmallBlock(BlockSize) && ReleaseType == ReleaseToOS::Normal)
if (RegionPushedBytesDelta < Region->TryReleaseThreshold)
return false;

if (ReleaseType == ReleaseToOS::Normal) {
const s32 IntervalMs = atomic_load_relaxed(&ReleaseToOsIntervalMs);
if (IntervalMs < 0)
if (RegionPushedBytesDelta < Region->ReleaseInfo.TryReleaseThreshold / 2)
return false;

const u64 IntervalNs =
static_cast<u64>(atomic_load_relaxed(&ReleaseToOsIntervalMs)) *
1000000;
if (IntervalNs < 0)
return false;

// The constant 8 here is selected from profiling some apps and the number
// of unreleased pages in the large size classes is around 16 pages or
// more. Choose half of it as a heuristic and which also avoids page
// release every time for every pushBlocks() attempt by large blocks.
const bool ByPassReleaseInterval =
isLargeBlock(BlockSize) && RegionPushedBytesDelta > 8 * PageSize;
if (!ByPassReleaseInterval) {
if (Region->ReleaseInfo.LastReleaseAtNs +
static_cast<u64>(IntervalMs) * 1000000 >
getMonotonicTimeFast()) {
// Memory was returned recently.
const u64 CurTimeNs = getMonotonicTimeFast();
const u64 DiffSinceLastReleaseNs =
CurTimeNs - Region->ReleaseInfo.LastReleaseAtNs;

// At here, `RegionPushedBytesDelta` is more than half of
// `TryReleaseThreshold`. If the last release happened 2 release interval
// before, we will still try to see if there's any chance to release some
// memory even it doesn't exceed the threshold.
if (RegionPushedBytesDelta < Region->ReleaseInfo.TryReleaseThreshold) {
// We want the threshold to have a shorter response time to the variant
// memory usage patterns. According to data collected during experiments
// (which were done with 1, 2, 4, 8 intervals), `2` strikes the better
// balance between the memory usage and number of page release attempts.
if (DiffSinceLastReleaseNs < 2 * IntervalNs)
return false;
}
} else if (DiffSinceLastReleaseNs < IntervalNs) {
// In this case, we are over the threshold but we just did some page
// release in the same release interval. This is a hint that we may want
// a higher threshold so that we can release more memory at once.
// `TryReleaseThreshold` will be adjusted according to how many bytes
// are not released, i.e., the `PendingPushedBytesdelta` here.
// TODO(chiahungduan): Apply the same adjustment strategy to small
// blocks.
if (!isSmallBlock(BlockSize))
Region->ReleaseInfo.PendingPushedBytesDelta = RegionPushedBytesDelta;

// Memory was returned recently.
return false;
}
} // if (ReleaseType == ReleaseToOS::Normal)

Expand All @@ -1397,10 +1452,10 @@ template <typename Config> class SizeClassAllocator64 {
SinglyLinkedList<BatchGroupT> GroupsToRelease;

// We are examining each group and will take the minimum distance to the
// release threshold as the next Region::TryReleaseThreshold(). Note that if
// the size of free blocks has reached the release threshold, the distance
// to the next release will be PageSize * SmallerBlockReleasePageDelta. See
// the comment on `SmallerBlockReleasePageDelta` for more details.
// release threshold as the next `TryReleaseThreshold`. Note that if the
// size of free blocks has reached the release threshold, the distance to
// the next release will be PageSize * SmallerBlockReleasePageDelta. See the
// comment on `SmallerBlockReleasePageDelta` for more details.
uptr MinDistToThreshold = GroupSize;

for (BatchGroupT *BG = Region->FreeListInfo.BlockList.front(),
Expand Down Expand Up @@ -1548,7 +1603,7 @@ template <typename Config> class SizeClassAllocator64 {
// back to normal.
if (MinDistToThreshold == GroupSize)
MinDistToThreshold = PageSize * SmallerBlockReleasePageDelta;
Region->TryReleaseThreshold = MinDistToThreshold;
Region->ReleaseInfo.TryReleaseThreshold = MinDistToThreshold;
}

return GroupsToRelease;
Expand Down
32 changes: 0 additions & 32 deletions compiler-rt/test/sanitizer_common/TestCases/Darwin/freadlink.c

This file was deleted.

2 changes: 1 addition & 1 deletion flang/docs/Intrinsics.md
Original file line number Diff line number Diff line change
Expand Up @@ -765,7 +765,7 @@ This phase currently supports all the intrinsic procedures listed above but the
| Coarray intrinsic functions | COSHAPE |
| Object characteristic inquiry functions | ALLOCATED, ASSOCIATED, EXTENDS_TYPE_OF, IS_CONTIGUOUS, PRESENT, RANK, SAME_TYPE, STORAGE_SIZE |
| Type inquiry intrinsic functions | BIT_SIZE, DIGITS, EPSILON, HUGE, KIND, MAXEXPONENT, MINEXPONENT, NEW_LINE, PRECISION, RADIX, RANGE, TINY|
| Non-standard intrinsic functions | AND, OR, XOR, SHIFT, ZEXT, IZEXT, COSD, SIND, TAND, ACOSD, ASIND, ATAND, ATAN2D, COMPL, EQV, NEQV, INT8, JINT, JNINT, KNINT, QCMPLX, DREAL, DFLOAT, QEXT, QFLOAT, QREAL, DNUM, NUM, JNUM, KNUM, QNUM, RNUM, RAN, RANF, ILEN, SIZEOF, MCLOCK, SECNDS, COTAN, IBCHNG, ISHA, ISHC, ISHL, IXOR, IARG, IARGC, NARGS, GETPID, NUMARG, BADDRESS, IADDR, CACHESIZE, EOF, FP_CLASS, INT_PTR_KIND, ISNAN, MALLOC, FREE |
| Non-standard intrinsic functions | AND, OR, XOR, SHIFT, ZEXT, IZEXT, COSD, SIND, TAND, ACOSD, ASIND, ATAND, ATAN2D, COMPL, EQV, NEQV, INT8, JINT, JNINT, KNINT, QCMPLX, DREAL, DFLOAT, QEXT, QFLOAT, QREAL, DNUM, NUM, JNUM, KNUM, QNUM, RNUM, RAN, RANF, ILEN, SIZEOF, MCLOCK, SECNDS, COTAN, IBCHNG, ISHA, ISHC, ISHL, IXOR, IARG, IARGC, NARGS, GETPID, NUMARG, BADDRESS, IADDR, CACHESIZE, EOF, FP_CLASS, INT_PTR_KIND, ISNAN, MALLOC, FREE, GETUID, GETGID |
| Intrinsic subroutines |MVBITS (elemental), CPU_TIME, DATE_AND_TIME, EVENT_QUERY, EXECUTE_COMMAND_LINE, GET_COMMAND, GET_COMMAND_ARGUMENT, GET_ENVIRONMENT_VARIABLE, MOVE_ALLOC, RANDOM_INIT, RANDOM_NUMBER, RANDOM_SEED, SIGNAL, SLEEP, SYSTEM, SYSTEM_CLOCK |
| Atomic intrinsic subroutines | ATOMIC_ADD |
| Collective intrinsic subroutines | CO_REDUCE |
Expand Down
79 changes: 6 additions & 73 deletions flang/include/flang/Common/Fortran-features.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "flang/Common/Fortran.h"
#include "flang/Common/enum-set.h"
#include "flang/Common/idioms.h"
#include <optional>
#include <vector>

namespace Fortran::common {
Expand Down Expand Up @@ -48,7 +49,7 @@ ENUM_CLASS(LanguageFeature, BackslashEscapes, OldDebugLines,
ImpliedDoIndexScope, DistinctCommonSizes, OddIndexVariableRestrictions,
IndistinguishableSpecifics, SubroutineAndFunctionSpecifics,
EmptySequenceType, NonSequenceCrayPointee, BranchIntoConstruct,
BadBranchTarget, ConvertedArgument, HollerithPolymorphic, ListDirectedSize,
BadBranchTarget, HollerithPolymorphic, ListDirectedSize,
NonBindCInteroperability, CudaManaged, CudaUnified,
PolymorphicActualAllocatableOrPointerToMonomorphicDummy, RelaxedPureDummy,
UndefinableAsynchronousOrVolatileActual, AutomaticInMainProgram, PrintCptr,
Expand Down Expand Up @@ -76,80 +77,12 @@ ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable,
using LanguageFeatures = EnumSet<LanguageFeature, LanguageFeature_enumSize>;
using UsageWarnings = EnumSet<UsageWarning, UsageWarning_enumSize>;

std::optional<LanguageFeature> FindLanguageFeature(const char *);
std::optional<UsageWarning> FindUsageWarning(const char *);

class LanguageFeatureControl {
public:
LanguageFeatureControl() {
// These features must be explicitly enabled by command line options.
disable_.set(LanguageFeature::OldDebugLines);
disable_.set(LanguageFeature::OpenACC);
disable_.set(LanguageFeature::OpenMP);
disable_.set(LanguageFeature::CUDA); // !@cuf
disable_.set(LanguageFeature::CudaManaged);
disable_.set(LanguageFeature::CudaUnified);
disable_.set(LanguageFeature::ImplicitNoneTypeNever);
disable_.set(LanguageFeature::ImplicitNoneTypeAlways);
disable_.set(LanguageFeature::DefaultSave);
disable_.set(LanguageFeature::SaveMainProgram);
// These features, if enabled, conflict with valid standard usage,
// so there are disabled here by default.
disable_.set(LanguageFeature::BackslashEscapes);
disable_.set(LanguageFeature::LogicalAbbreviations);
disable_.set(LanguageFeature::XOROperator);
disable_.set(LanguageFeature::OldStyleParameter);
// These warnings are enabled by default, but only because they used
// to be unconditional. TODO: prune this list
warnLanguage_.set(LanguageFeature::ExponentMatchingKindParam);
warnLanguage_.set(LanguageFeature::RedundantAttribute);
warnLanguage_.set(LanguageFeature::SubroutineAndFunctionSpecifics);
warnLanguage_.set(LanguageFeature::EmptySequenceType);
warnLanguage_.set(LanguageFeature::NonSequenceCrayPointee);
warnLanguage_.set(LanguageFeature::BranchIntoConstruct);
warnLanguage_.set(LanguageFeature::BadBranchTarget);
warnLanguage_.set(LanguageFeature::ConvertedArgument);
warnLanguage_.set(LanguageFeature::HollerithPolymorphic);
warnLanguage_.set(LanguageFeature::ListDirectedSize);
warnUsage_.set(UsageWarning::ShortArrayActual);
warnUsage_.set(UsageWarning::FoldingException);
warnUsage_.set(UsageWarning::FoldingAvoidsRuntimeCrash);
warnUsage_.set(UsageWarning::FoldingValueChecks);
warnUsage_.set(UsageWarning::FoldingFailure);
warnUsage_.set(UsageWarning::FoldingLimit);
warnUsage_.set(UsageWarning::Interoperability);
warnUsage_.set(UsageWarning::Bounds);
warnUsage_.set(UsageWarning::Preprocessing);
warnUsage_.set(UsageWarning::Scanning);
warnUsage_.set(UsageWarning::OpenAccUsage);
warnUsage_.set(UsageWarning::ProcPointerCompatibility);
warnUsage_.set(UsageWarning::VoidMold);
warnUsage_.set(UsageWarning::KnownBadImplicitInterface);
warnUsage_.set(UsageWarning::EmptyCase);
warnUsage_.set(UsageWarning::CaseOverflow);
warnUsage_.set(UsageWarning::CUDAUsage);
warnUsage_.set(UsageWarning::IgnoreTKRUsage);
warnUsage_.set(UsageWarning::ExternalInterfaceMismatch);
warnUsage_.set(UsageWarning::DefinedOperatorArgs);
warnUsage_.set(UsageWarning::Final);
warnUsage_.set(UsageWarning::ZeroDoStep);
warnUsage_.set(UsageWarning::UnusedForallIndex);
warnUsage_.set(UsageWarning::OpenMPUsage);
warnUsage_.set(UsageWarning::ModuleFile);
warnUsage_.set(UsageWarning::DataLength);
warnUsage_.set(UsageWarning::IgnoredDirective);
warnUsage_.set(UsageWarning::HomonymousSpecific);
warnUsage_.set(UsageWarning::HomonymousResult);
warnUsage_.set(UsageWarning::IgnoredIntrinsicFunctionType);
warnUsage_.set(UsageWarning::PreviousScalarUse);
warnUsage_.set(UsageWarning::RedeclaredInaccessibleComponent);
warnUsage_.set(UsageWarning::ImplicitShared);
warnUsage_.set(UsageWarning::IndexVarRedefinition);
warnUsage_.set(UsageWarning::IncompatibleImplicitInterfaces);
warnUsage_.set(UsageWarning::BadTypeForTarget);
warnUsage_.set(UsageWarning::VectorSubscriptFinalization);
warnUsage_.set(UsageWarning::UndefinedFunctionResult);
warnUsage_.set(UsageWarning::UselessIomsg);
// New warnings, on by default
warnLanguage_.set(LanguageFeature::SavedLocalInSpecExpr);
}
LanguageFeatureControl();
LanguageFeatureControl(const LanguageFeatureControl &) = default;

void Enable(LanguageFeature f, bool yes = true) { disable_.set(f, !yes); }
Expand Down
6 changes: 6 additions & 0 deletions flang/include/flang/Evaluate/target.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@ class TargetCharacteristics {
bool isPPC() const { return isPPC_; }
void set_isPPC(bool isPPC = false);

bool isOSWindows() const { return isOSWindows_; }
void set_isOSWindows(bool isOSWindows = false) {
isOSWindows_ = isOSWindows;
};

IeeeFeatures &ieeeFeatures() { return ieeeFeatures_; }
const IeeeFeatures &ieeeFeatures() const { return ieeeFeatures_; }

Expand All @@ -111,6 +116,7 @@ class TargetCharacteristics {
std::uint8_t align_[common::TypeCategory_enumSize][maxKind]{};
bool isBigEndian_{false};
bool isPPC_{false};
bool isOSWindows_{false};
bool areSubnormalsFlushedToZero_{false};
Rounding roundingMode_{defaultRounding};
std::size_t procedurePointerByteSize_{8};
Expand Down
4 changes: 4 additions & 0 deletions flang/include/flang/Optimizer/Builder/IntrinsicCall.h
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,10 @@ struct IntrinsicLibrary {
llvm::ArrayRef<mlir::Value> args);
void genGetCommandArgument(mlir::ArrayRef<fir::ExtendedValue> args);
void genGetEnvironmentVariable(llvm::ArrayRef<fir::ExtendedValue>);
mlir::Value genGetGID(mlir::Type resultType,
llvm::ArrayRef<mlir::Value> args);
mlir::Value genGetUID(mlir::Type resultType,
llvm::ArrayRef<mlir::Value> args);
fir::ExtendedValue genIall(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
mlir::Value genIand(mlir::Type, llvm::ArrayRef<mlir::Value>);
fir::ExtendedValue genIany(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
Expand Down
4 changes: 4 additions & 0 deletions flang/include/flang/Optimizer/Builder/Runtime/Intrinsics.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ void genEtime(fir::FirOpBuilder &builder, mlir::Location loc,
mlir::Value values, mlir::Value time);

void genFree(fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value ptr);

mlir::Value genGetUID(fir::FirOpBuilder &, mlir::Location);
mlir::Value genGetGID(fir::FirOpBuilder &, mlir::Location);

mlir::Value genMalloc(fir::FirOpBuilder &builder, mlir::Location loc,
mlir::Value size);

Expand Down
23 changes: 0 additions & 23 deletions flang/include/flang/Optimizer/Dialect/FIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -2609,29 +2609,6 @@ class fir_UnaryArithmeticOp<string mnemonic, list<Trait> traits = []> :
let assemblyFormat = "operands attr-dict `:` type($result)";
}

def fir_ConstcOp : fir_Op<"constc", [NoMemoryEffect]> {
let summary = "create a complex constant";

let description = [{
A complex constant. Similar to the standard dialect complex type, but this
extension allows constants with APFloat values that are not supported in
the standard dialect.
}];

let results = (outs fir_ComplexType);

let hasCustomAssemblyFormat = 1;
let hasVerifier = 1;

let extraClassDeclaration = [{
static constexpr llvm::StringRef getRealAttrName() { return "real"; }
static constexpr llvm::StringRef getImagAttrName() { return "imaginary"; }

mlir::Attribute getReal() { return (*this)->getAttr(getRealAttrName()); }
mlir::Attribute getImaginary() { return (*this)->getAttr(getImagAttrName()); }
}];
}

class ComplexUnaryArithmeticOp<string mnemonic, list<Trait> traits = []> :
fir_UnaryArithmeticOp<mnemonic, traits>,
Arguments<(ins fir_ComplexType:$operand)>;
Expand Down
2 changes: 2 additions & 0 deletions flang/include/flang/Parser/dump-parse-tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,8 @@ class ParseTreeDumper {
NODE(parser, OmpEndSectionsDirective)
NODE(parser, OmpIfClause)
NODE_ENUM(OmpIfClause, DirectiveNameModifier)
NODE_ENUM(OmpLastprivateClause, LastprivateModifier)
NODE(parser, OmpLastprivateClause)
NODE(parser, OmpLinearClause)
NODE(OmpLinearClause, WithModifier)
NODE(OmpLinearClause, WithoutModifier)
Expand Down
90 changes: 88 additions & 2 deletions flang/include/flang/Parser/message.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "char-block.h"
#include "char-set.h"
#include "provenance.h"
#include "flang/Common/Fortran-features.h"
#include "flang/Common/idioms.h"
#include "flang/Common/reference-counted.h"
#include "flang/Common/restorer.h"
Expand Down Expand Up @@ -202,6 +203,26 @@ class Message : public common::ReferenceCounted<Message> {
Message(ProvenanceRange pr, const MessageExpectedText &t)
: location_{pr}, text_{t} {}

Message(common::LanguageFeature feature, ProvenanceRange pr,
const MessageFixedText &t)
: location_{pr}, text_{t}, languageFeature_{feature} {}
Message(common::LanguageFeature feature, ProvenanceRange pr,
const MessageFormattedText &s)
: location_{pr}, text_{s}, languageFeature_{feature} {}
Message(common::LanguageFeature feature, ProvenanceRange pr,
MessageFormattedText &&s)
: location_{pr}, text_{std::move(s)}, languageFeature_{feature} {}

Message(common::UsageWarning warning, ProvenanceRange pr,
const MessageFixedText &t)
: location_{pr}, text_{t}, usageWarning_{warning} {}
Message(common::UsageWarning warning, ProvenanceRange pr,
const MessageFormattedText &s)
: location_{pr}, text_{s}, usageWarning_{warning} {}
Message(common::UsageWarning warning, ProvenanceRange pr,
MessageFormattedText &&s)
: location_{pr}, text_{std::move(s)}, usageWarning_{warning} {}

Message(CharBlock csr, const MessageFixedText &t)
: location_{csr}, text_{t} {}
Message(CharBlock csr, const MessageFormattedText &s)
Expand All @@ -211,10 +232,41 @@ class Message : public common::ReferenceCounted<Message> {
Message(CharBlock csr, const MessageExpectedText &t)
: location_{csr}, text_{t} {}

Message(
common::LanguageFeature feature, CharBlock csr, const MessageFixedText &t)
: location_{csr}, text_{t}, languageFeature_{feature} {}
Message(common::LanguageFeature feature, CharBlock csr,
const MessageFormattedText &s)
: location_{csr}, text_{s}, languageFeature_{feature} {}
Message(
common::LanguageFeature feature, CharBlock csr, MessageFormattedText &&s)
: location_{csr}, text_{std::move(s)}, languageFeature_{feature} {}

Message(
common::UsageWarning warning, CharBlock csr, const MessageFixedText &t)
: location_{csr}, text_{t}, usageWarning_{warning} {}
Message(common::UsageWarning warning, CharBlock csr,
const MessageFormattedText &s)
: location_{csr}, text_{s}, usageWarning_{warning} {}
Message(common::UsageWarning warning, CharBlock csr, MessageFormattedText &&s)
: location_{csr}, text_{std::move(s)}, usageWarning_{warning} {}

template <typename RANGE, typename A, typename... As>
Message(RANGE r, const MessageFixedText &t, A &&x, As &&...xs)
: location_{r}, text_{MessageFormattedText{
t, std::forward<A>(x), std::forward<As>(xs)...}} {}
template <typename RANGE, typename A, typename... As>
Message(common::LanguageFeature feature, RANGE r, const MessageFixedText &t,
A &&x, As &&...xs)
: location_{r}, text_{MessageFormattedText{
t, std::forward<A>(x), std::forward<As>(xs)...}},
languageFeature_{feature} {}
template <typename RANGE, typename A, typename... As>
Message(common::UsageWarning warning, RANGE r, const MessageFixedText &t,
A &&x, As &&...xs)
: location_{r}, text_{MessageFormattedText{
t, std::forward<A>(x), std::forward<As>(xs)...}},
usageWarning_{warning} {}

Reference attachment() const { return attachment_; }

Expand All @@ -232,6 +284,10 @@ class Message : public common::ReferenceCounted<Message> {
bool IsFatal() const;
Severity severity() const;
Message &set_severity(Severity);
std::optional<common::LanguageFeature> languageFeature() const;
Message &set_languageFeature(common::LanguageFeature);
std::optional<common::UsageWarning> usageWarning() const;
Message &set_usageWarning(common::UsageWarning);
std::string ToString() const;
std::optional<ProvenanceRange> GetProvenanceRange(
const AllCookedSources &) const;
Expand All @@ -256,6 +312,8 @@ class Message : public common::ReferenceCounted<Message> {
text_;
bool attachmentIsContext_{false};
Reference attachment_;
std::optional<common::LanguageFeature> languageFeature_;
std::optional<common::UsageWarning> usageWarning_;
};

class Messages {
Expand All @@ -275,6 +333,16 @@ class Messages {
return messages_.emplace_back(std::forward<A>(args)...);
}

template <typename... A>
Message &Say(common::LanguageFeature feature, A &&...args) {
return Say(std::forward<A>(args)...).set_languageFeature(feature);
}

template <typename... A>
Message &Say(common::UsageWarning warning, A &&...args) {
return Say(std::forward<A>(args)...).set_usageWarning(warning);
}

void Annex(Messages &&that) {
messages_.splice(messages_.end(), that.messages_);
}
Expand Down Expand Up @@ -330,6 +398,10 @@ class ContextualMessages {
return common::ScopedSet(messages_, nullptr);
}

template <typename... A> Message *Say(A &&...args) {
return Say(at_, std::forward<A>(args)...);
}

template <typename... A> Message *Say(CharBlock at, A &&...args) {
if (messages_ != nullptr) {
auto &msg{messages_->Say(at, std::forward<A>(args)...)};
Expand All @@ -347,8 +419,22 @@ class ContextualMessages {
return Say(at.value_or(at_), std::forward<A>(args)...);
}

template <typename... A> Message *Say(A &&...args) {
return Say(at_, std::forward<A>(args)...);
template <typename... A>
Message *Say(common::LanguageFeature feature, A &&...args) {
Message *msg{Say(std::forward<A>(args)...)};
if (msg) {
msg->set_languageFeature(feature);
}
return msg;
}

template <typename... A>
Message *Say(common::UsageWarning warning, A &&...args) {
Message *msg{Say(std::forward<A>(args)...)};
if (msg) {
msg->set_usageWarning(warning);
}
return msg;
}

Message *Say(Message &&msg) {
Expand Down
9 changes: 9 additions & 0 deletions flang/include/flang/Parser/parse-tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -3648,6 +3648,15 @@ struct OmpAtomicDefaultMemOrderClause {
OmpAtomicDefaultMemOrderClause, common::OmpAtomicDefaultMemOrderType);
};

// OMP 5.0 2.19.4.5 lastprivate-clause ->
// LASTPRIVATE ([lastprivate-modifier :] list)
// lastprivate-modifier -> CONDITIONAL
struct OmpLastprivateClause {
TUPLE_CLASS_BOILERPLATE(OmpLastprivateClause);
ENUM_CLASS(LastprivateModifier, Conditional);
std::tuple<std::optional<LastprivateModifier>, OmpObjectList> t;
};

// OpenMP Clauses
struct OmpClause {
UNION_CLASS_BOILERPLATE(OmpClause);
Expand Down
14 changes: 14 additions & 0 deletions flang/include/flang/Runtime/extensions.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@
#include <cstddef>
#include <cstdint>

#ifdef _WIN32
// UID and GID don't exist on Windows, these exist to avoid errors.
typedef std::uint32_t uid_t;
typedef std::uint32_t gid_t;
#else
#include "sys/types.h" //pid_t
#endif

extern "C" {

// CALL FLUSH(n) antedates the Fortran 2003 FLUSH statement.
Expand All @@ -37,6 +45,12 @@ std::int32_t FORTRAN_PROCEDURE_NAME(iargc)();
void FORTRAN_PROCEDURE_NAME(getarg)(
std::int32_t &n, char *arg, std::int64_t length);

// Calls getgid()
gid_t RTNAME(GetGID)();

// Calls getuid()
uid_t RTNAME(GetUID)();

// GNU extension subroutine GETLOG(C).
void FORTRAN_PROCEDURE_NAME(getlog)(char *name, std::int64_t length);

Expand Down
10 changes: 10 additions & 0 deletions flang/include/flang/Semantics/expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,16 @@ class ExpressionAnalyzer {
template <typename... A> parser::Message *Say(A &&...args) {
return GetContextualMessages().Say(std::forward<A>(args)...);
}
template <typename FeatureOrUsageWarning, typename... A>
parser::Message *Warn(
FeatureOrUsageWarning warning, parser::CharBlock at, A &&...args) {
return context_.Warn(warning, at, std::forward<A>(args)...);
}
template <typename FeatureOrUsageWarning, typename... A>
parser::Message *Warn(FeatureOrUsageWarning warning, A &&...args) {
return Warn(
warning, GetContextualMessages().at(), std::forward<A>(args)...);
}

template <typename T, typename... A>
parser::Message *SayAt(const T &parsed, A &&...args) {
Expand Down
20 changes: 19 additions & 1 deletion flang/include/flang/Semantics/semantics.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,24 @@ class SemanticsContext {
return message;
}

template <typename FeatureOrUsageWarning, typename... A>
parser::Message *Warn(
FeatureOrUsageWarning warning, parser::CharBlock at, A &&...args) {
if (languageFeatures_.ShouldWarn(warning) && !IsInModuleFile(at)) {
parser::Message &msg{
messages_.Say(warning, at, std::forward<A>(args)...)};
return &msg;
} else {
return nullptr;
}
}

template <typename FeatureOrUsageWarning, typename... A>
parser::Message *Warn(FeatureOrUsageWarning warning, A &&...args) {
CHECK(location_);
return Warn(warning, *location_, std::forward<A>(args)...);
}

const Scope &FindScope(parser::CharBlock) const;
Scope &FindScope(parser::CharBlock);
void UpdateScopeIndex(Scope &, parser::CharBlock);
Expand Down Expand Up @@ -270,7 +288,7 @@ class SemanticsContext {
std::multimap<parser::CharBlock, Scope &, ScopeIndexComparator>;
ScopeIndex::iterator SearchScopeIndex(parser::CharBlock);

void CheckIndexVarRedefine(
parser::Message *CheckIndexVarRedefine(
const parser::CharBlock &, const Symbol &, parser::MessageFixedText &&);
void CheckError(const Symbol &);

Expand Down
3 changes: 3 additions & 0 deletions flang/include/flang/Tools/TargetSetup.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ namespace Fortran::tools {
if (targetTriple.isPPC())
targetCharacteristics.set_isPPC(true);

if (targetTriple.isOSWindows())
targetCharacteristics.set_isOSWindows(true);

// TODO: use target machine data layout to set-up the target characteristics
// type size and alignment info.
}
Expand Down
125 changes: 125 additions & 0 deletions flang/lib/Common/Fortran-features.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,131 @@

namespace Fortran::common {

LanguageFeatureControl::LanguageFeatureControl() {
// These features must be explicitly enabled by command line options.
disable_.set(LanguageFeature::OldDebugLines);
disable_.set(LanguageFeature::OpenACC);
disable_.set(LanguageFeature::OpenMP);
disable_.set(LanguageFeature::CUDA); // !@cuf
disable_.set(LanguageFeature::CudaManaged);
disable_.set(LanguageFeature::CudaUnified);
disable_.set(LanguageFeature::ImplicitNoneTypeNever);
disable_.set(LanguageFeature::ImplicitNoneTypeAlways);
disable_.set(LanguageFeature::DefaultSave);
disable_.set(LanguageFeature::SaveMainProgram);
// These features, if enabled, conflict with valid standard usage,
// so there are disabled here by default.
disable_.set(LanguageFeature::BackslashEscapes);
disable_.set(LanguageFeature::LogicalAbbreviations);
disable_.set(LanguageFeature::XOROperator);
disable_.set(LanguageFeature::OldStyleParameter);
// These warnings are enabled by default, but only because they used
// to be unconditional. TODO: prune this list
warnLanguage_.set(LanguageFeature::ExponentMatchingKindParam);
warnLanguage_.set(LanguageFeature::RedundantAttribute);
warnLanguage_.set(LanguageFeature::SubroutineAndFunctionSpecifics);
warnLanguage_.set(LanguageFeature::EmptySequenceType);
warnLanguage_.set(LanguageFeature::NonSequenceCrayPointee);
warnLanguage_.set(LanguageFeature::BranchIntoConstruct);
warnLanguage_.set(LanguageFeature::BadBranchTarget);
warnLanguage_.set(LanguageFeature::HollerithPolymorphic);
warnLanguage_.set(LanguageFeature::ListDirectedSize);
warnUsage_.set(UsageWarning::ShortArrayActual);
warnUsage_.set(UsageWarning::FoldingException);
warnUsage_.set(UsageWarning::FoldingAvoidsRuntimeCrash);
warnUsage_.set(UsageWarning::FoldingValueChecks);
warnUsage_.set(UsageWarning::FoldingFailure);
warnUsage_.set(UsageWarning::FoldingLimit);
warnUsage_.set(UsageWarning::Interoperability);
warnUsage_.set(UsageWarning::Bounds);
warnUsage_.set(UsageWarning::Preprocessing);
warnUsage_.set(UsageWarning::Scanning);
warnUsage_.set(UsageWarning::OpenAccUsage);
warnUsage_.set(UsageWarning::ProcPointerCompatibility);
warnUsage_.set(UsageWarning::VoidMold);
warnUsage_.set(UsageWarning::KnownBadImplicitInterface);
warnUsage_.set(UsageWarning::EmptyCase);
warnUsage_.set(UsageWarning::CaseOverflow);
warnUsage_.set(UsageWarning::CUDAUsage);
warnUsage_.set(UsageWarning::IgnoreTKRUsage);
warnUsage_.set(UsageWarning::ExternalInterfaceMismatch);
warnUsage_.set(UsageWarning::DefinedOperatorArgs);
warnUsage_.set(UsageWarning::Final);
warnUsage_.set(UsageWarning::ZeroDoStep);
warnUsage_.set(UsageWarning::UnusedForallIndex);
warnUsage_.set(UsageWarning::OpenMPUsage);
warnUsage_.set(UsageWarning::ModuleFile);
warnUsage_.set(UsageWarning::DataLength);
warnUsage_.set(UsageWarning::IgnoredDirective);
warnUsage_.set(UsageWarning::HomonymousSpecific);
warnUsage_.set(UsageWarning::HomonymousResult);
warnUsage_.set(UsageWarning::IgnoredIntrinsicFunctionType);
warnUsage_.set(UsageWarning::PreviousScalarUse);
warnUsage_.set(UsageWarning::RedeclaredInaccessibleComponent);
warnUsage_.set(UsageWarning::ImplicitShared);
warnUsage_.set(UsageWarning::IndexVarRedefinition);
warnUsage_.set(UsageWarning::IncompatibleImplicitInterfaces);
warnUsage_.set(UsageWarning::BadTypeForTarget);
warnUsage_.set(UsageWarning::VectorSubscriptFinalization);
warnUsage_.set(UsageWarning::UndefinedFunctionResult);
warnUsage_.set(UsageWarning::UselessIomsg);
// New warnings, on by default
warnLanguage_.set(LanguageFeature::SavedLocalInSpecExpr);
}

// Ignore case and any inserted punctuation (like '-'/'_')
static std::optional<char> GetWarningChar(char ch) {
if (ch >= 'a' && ch <= 'z') {
return ch;
} else if (ch >= 'A' && ch <= 'Z') {
return ch - 'A' + 'a';
} else if (ch >= '0' && ch <= '9') {
return ch;
} else {
return std::nullopt;
}
}

static bool WarningNameMatch(const char *a, const char *b) {
while (true) {
auto ach{GetWarningChar(*a)};
while (!ach && *a) {
ach = GetWarningChar(*++a);
}
auto bch{GetWarningChar(*b)};
while (!bch && *b) {
bch = GetWarningChar(*++b);
}
if (!ach && !bch) {
return true;
} else if (!ach || !bch || *ach != *bch) {
return false;
}
++a, ++b;
}
}

template <typename ENUM, std::size_t N>
std::optional<ENUM> ScanEnum(const char *name) {
if (name) {
for (std::size_t j{0}; j < N; ++j) {
auto feature{static_cast<ENUM>(j)};
if (WarningNameMatch(name, EnumToString(feature).data())) {
return feature;
}
}
}
return std::nullopt;
}

std::optional<LanguageFeature> FindLanguageFeature(const char *name) {
return ScanEnum<LanguageFeature, LanguageFeature_enumSize>(name);
}

std::optional<UsageWarning> FindUsageWarning(const char *name) {
return ScanEnum<UsageWarning, UsageWarning_enumSize>(name);
}

std::vector<const char *> LanguageFeatureControl::GetNames(
LogicalOperator opr) const {
std::vector<const char *> result;
Expand Down
Loading