Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,7 @@ Bug Fixes to Attribute Support
``[[gnu::error("some error")]]`` now correctly triggers an error. (#GH146520)
- Fix a crash when the function name is empty in the `swift_name` attribute. (#GH157075)
- Fixes crashes or missing diagnostics with the `device_kernel` attribute. (#GH161905)
- Fix ``cleanup`` attribute by delaying type checks after the type is deduced. (#GH129631)

Bug Fixes to C++ Support
^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,9 @@ class Attr {
// our existing general parsing we need to have a separate flag that
// opts an attribute into strict parsing of attribute parameters
bit StrictEnumParameters = 0;
// Set to true for attributes which have Sema checks which requires the type
// to be deduced.
bit IsTypeDependent = 0;
// Lists language options, one of which is required to be true for the
// attribute to be applicable. If empty, no language options are required.
list<LangOpt> LangOpts = [];
Expand Down Expand Up @@ -1408,6 +1411,7 @@ def Cleanup : InheritableAttr {
let Args = [DeclArgument<Function, "FunctionDecl">];
let Subjects = SubjectList<[LocalVar]>;
let Documentation = [CleanupDocs];
bit IsTypeDependent = 1;
// FIXME: DeclArgument should be reworked to also store the
// Expr instead of adding attr specific hacks like the following.
// See the discussion in https://github.com/llvm/llvm-project/pull/14023.
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Sema/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ clang_tablegen(AttrParsedAttrKinds.inc -gen-clang-attr-parsed-attr-kinds
SOURCE ../Basic/Attr.td
TARGET ClangAttrParsedAttrKinds)

clang_tablegen(AttrIsTypeDependent.inc -gen-clang-attr-is-type-dependent
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
SOURCE ../Basic/Attr.td
TARGET ClangAttrIsTypeDependent)

clang_tablegen(AttrSpellingListIndex.inc -gen-clang-attr-spelling-index
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
SOURCE ../Basic/Attr.td
Expand Down
8 changes: 8 additions & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -4461,6 +4461,10 @@ class Sema final : public SemaBase {
NamedDecl *New, Decl *Old,
AvailabilityMergeKind AMK = AvailabilityMergeKind::Redeclaration);

/// CheckAttributesOnDeducedType - Calls Sema functions for attributes that
/// requires the type to be deduced.
void CheckAttributesOnDeducedType(Expr *E, Decl *D);

/// MergeTypedefNameDecl - We just parsed a typedef 'New' which has the
/// same name and scope as a previous declaration 'Old'. Figure out
/// how to resolve this situation, merging decls or emitting
Expand Down Expand Up @@ -4765,6 +4769,8 @@ class Sema final : public SemaBase {
// linkage or not.
static bool mightHaveNonExternalLinkage(const DeclaratorDecl *FD);

#include "clang/Sema/AttrIsTypeDependent.inc"

///@}

//
Expand Down Expand Up @@ -15479,6 +15485,8 @@ class Sema final : public SemaBase {
std::optional<FunctionEffectMode>
ActOnEffectExpression(Expr *CondExpr, StringRef AttributeName);

void ActOnCleanupAttr(Expr *E, Decl *D, const Attr *A);

private:
/// The implementation of RequireCompleteType
bool RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
Expand Down
12 changes: 12 additions & 0 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3354,6 +3354,15 @@ void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old,
if (!foundAny) New->dropAttrs();
}

void Sema::CheckAttributesOnDeducedType(Expr *E, Decl *D) {
if (!D->hasAttrs())
return;

for (const Attr *A : D->getAttrs()) {
checkAttrIsTypeDependent(E, D, A);
}
}

// Returns the number of added attributes.
template <class T>
static unsigned propagateAttribute(ParmVarDecl *To, const ParmVarDecl *From,
Expand Down Expand Up @@ -13797,6 +13806,8 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
return;
}

this->CheckAttributesOnDeducedType(Init, RealDecl);

// dllimport cannot be used on variable definitions.
if (VDecl->hasAttr<DLLImportAttr>() && !VDecl->isStaticDataMember()) {
Diag(VDecl->getLocation(), diag::err_attribute_dllimport_data_definition);
Expand Down Expand Up @@ -14587,6 +14598,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
Var->setInit(RecoveryExpr.get());
}

this->CheckAttributesOnDeducedType(Init.get(), RealDecl);
CheckCompleteVariableDeclaration(Var);
}
}
Expand Down
31 changes: 21 additions & 10 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3511,16 +3511,6 @@ static void handleCleanupAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}

// We're currently more strict than GCC about what function types we accept.
// If this ever proves to be a problem it should be easy to fix.
QualType Ty = S.Context.getPointerType(cast<VarDecl>(D)->getType());
QualType ParamTy = FD->getParamDecl(0)->getType();
if (!S.IsAssignConvertCompatible(S.CheckAssignmentConstraints(
FD->getParamDecl(0)->getLocation(), ParamTy, Ty))) {
S.Diag(Loc, diag::err_attribute_cleanup_func_arg_incompatible_type)
<< NI.getName() << ParamTy << Ty;
return;
}
VarDecl *VD = cast<VarDecl>(D);
// Create a reference to the variable declaration. This is a fake/dummy
// reference.
Expand Down Expand Up @@ -8311,3 +8301,24 @@ void Sema::redelayDiagnostics(DelayedDiagnosticPool &pool) {
assert(curPool && "re-emitting in undelayed context not supported");
curPool->steal(pool);
}

void Sema::ActOnCleanupAttr(Expr *E, Decl *D, const Attr *A) {
// Obtains the FunctionDecl that was found when handling the attribute
// earlier.
CleanupAttr *Attr = D->getAttr<CleanupAttr>();
FunctionDecl *FD = Attr->getFunctionDecl();
DeclarationNameInfo NI = FD->getNameInfo();

// We're currently more strict than GCC about what function types we accept.
// If this ever proves to be a problem it should be easy to fix.
QualType Ty = this->Context.getPointerType(cast<VarDecl>(D)->getType());
QualType ParamTy = FD->getParamDecl(0)->getType();
if (!this->IsAssignConvertCompatible(this->CheckAssignmentConstraints(
FD->getParamDecl(0)->getLocation(), ParamTy, Ty))) {
this->Diag(Attr->getArgLoc(),
diag::err_attribute_cleanup_func_arg_incompatible_type)
<< NI.getName() << ParamTy << Ty;
D->dropAttr<CleanupAttr>();
return;
}
}
10 changes: 10 additions & 0 deletions clang/test/Sema/type-dependent-attrs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// RUN: %clang_cc1 -std=c23 -fsyntax-only -verify %s

int open() { return 0; }
void close(typeof(open()) *) {}

void cleanup_attr() {
int fd_int [[gnu::cleanup(close)]] = open();
auto fd_auto [[gnu::cleanup(close)]] = open();
float fd_invalid [[gnu::cleanup(close)]] = open(); // expected-error {{'cleanup' function 'close' parameter has type 'typeof (open()) *' (aka 'int *') which is incompatible with type 'float *'}}
}
26 changes: 26 additions & 0 deletions clang/utils/TableGen/ClangAttrEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5061,6 +5061,32 @@ void EmitClangAttrParsedAttrKinds(const RecordKeeper &Records,
<< "}\n";
}

// Emits Sema calls for type dependent attributes
void EmitClangAttrIsTypeDependent(const RecordKeeper &Records,
raw_ostream &OS) {
emitSourceFileHeader("Attribute is type dependent", OS, Records);

std::set<StringRef> Seen;
for (const auto *A : Records.getAllDerivedDefinitions("Attr")) {
const Record &Attr = *A;
if (Attr.getValueAsBit("IsTypeDependent")) {
Seen.insert(Attr.getName());
}
}

OS << "void checkAttrIsTypeDependent(Expr *E, Decl *D, const Attr *A) {\n";
OS << " switch (A->getKind()) {\n";
for (const StringRef &SeenAttr : Seen) {
OS << " case attr::" << SeenAttr << ":\n";
OS << " ActOn" << SeenAttr << "Attr(E, D, A);\n";
OS << " break;\n";
}
OS << " default:\n";
OS << " break;\n";
OS << " }\n";
OS << "}\n";
}

// Emits the code to dump an attribute.
void EmitClangAttrTextNodeDump(const RecordKeeper &Records, raw_ostream &OS) {
emitSourceFileHeader("Attribute text node dumper", OS, Records);
Expand Down
7 changes: 7 additions & 0 deletions clang/utils/TableGen/TableGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ enum ActionType {
GenClangAttrParsedAttrList,
GenClangAttrParsedAttrImpl,
GenClangAttrParsedAttrKinds,
GenClangAttrIsTypeDependent,
GenClangAttrTextNodeDump,
GenClangAttrNodeTraverse,
GenClangBasicReader,
Expand Down Expand Up @@ -179,6 +180,9 @@ cl::opt<ActionType> Action(
clEnumValN(GenClangAttrParsedAttrKinds,
"gen-clang-attr-parsed-attr-kinds",
"Generate a clang parsed attribute kinds"),
clEnumValN(GenClangAttrIsTypeDependent,
"gen-clang-attr-is-type-dependent",
"Generate clang is type dependent attribute code"),
clEnumValN(GenClangAttrTextNodeDump, "gen-clang-attr-text-node-dump",
"Generate clang attribute text node dumper"),
clEnumValN(GenClangAttrNodeTraverse, "gen-clang-attr-node-traverse",
Expand Down Expand Up @@ -423,6 +427,9 @@ bool ClangTableGenMain(raw_ostream &OS, const RecordKeeper &Records) {
case GenClangAttrParsedAttrKinds:
EmitClangAttrParsedAttrKinds(Records, OS);
break;
case GenClangAttrIsTypeDependent:
EmitClangAttrIsTypeDependent(Records, OS);
break;
case GenClangAttrTextNodeDump:
EmitClangAttrTextNodeDump(Records, OS);
break;
Expand Down
2 changes: 2 additions & 0 deletions clang/utils/TableGen/TableGenBackends.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ void EmitClangAttrParsedAttrImpl(const llvm::RecordKeeper &Records,
llvm::raw_ostream &OS);
void EmitClangAttrParsedAttrKinds(const llvm::RecordKeeper &Records,
llvm::raw_ostream &OS);
void EmitClangAttrIsTypeDependent(const llvm::RecordKeeper &Records,
llvm::raw_ostream &OS);
void EmitClangAttrTextNodeDump(const llvm::RecordKeeper &Records,
llvm::raw_ostream &OS);
void EmitClangAttrNodeTraverse(const llvm::RecordKeeper &Records,
Expand Down
7 changes: 7 additions & 0 deletions llvm/docs/TableGen/BackEnds.rst
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,13 @@ ClangAttrParsedAttrKinds
``AttributeList::getKind`` function, mapping a string (and syntax) to a parsed
attribute ``AttributeList::Kind`` enumeration.

ClangAttrIsTypeDependent
------------------------

**Purpose**: Creates ``AttrIsTypeDependent.inc``, which is used to implement the
``Sema::CheckAttributesOnDeducedType`` function, mapping an attribute kind to a
Sema function if it exists.

ClangAttrDump
-------------

Expand Down