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 @@ -447,6 +447,7 @@ Bug Fixes to Attribute Support
- Using ``[[gnu::cleanup(some_func)]]`` where some_func is annotated with
``[[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)
- Fix ``cleanup`` attribute by delaying type checks after the type is deduced. (#GH129631)

Bug Fixes to C++ Support
^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -4465,6 +4465,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 @@ -15483,6 +15487,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
18 changes: 18 additions & 0 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3354,6 +3354,21 @@ 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()) {
switch (A->getKind()) {
case attr::Cleanup:
ActOnCleanupAttr(E, D, A);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At one point it would be lovely to table-gen this whole function and have the handlers in a more organized place, probably in SemaDeclAttr.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had done an attempt with tablegen in my draft, but now that I think about it would make more sense to use tablegen again.

break;
default:
continue;
}
}
}

// Returns the number of added attributes.
template <class T>
static unsigned propagateAttribute(ParmVarDecl *To, const ParmVarDecl *From,
Expand Down Expand Up @@ -13797,6 +13812,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 +14604,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 @@ -8291,3 +8281,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 *'}}
}
Loading