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
11 changes: 11 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,17 @@ AST Dumping Potentially Breaking Changes

- Default arguments of template template parameters are pretty-printed now.

- Pretty-printing of ``asm`` attributes are now always the first attribute
on the right side of the declaration. Before we had, e.g.:

``__attribute__(("visibility")) asm("string")``

Now we have:

``asm("string") __attribute__(("visibility"))``

Which is accepted by both clang and gcc parsers.

Clang Frontend Potentially Breaking Changes
-------------------------------------------
- Members of anonymous unions/structs are now injected as ``IndirectFieldDecl``
Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -3961,6 +3961,13 @@ class Sema final : public SemaBase {
bool &AddToScope,
ArrayRef<BindingDecl *> Bindings = {});

private:
// Perform a check on an AsmLabel to verify its consistency and emit
// diagnostics in case of an error.
void CheckAsmLabel(Scope *S, Expr *AsmLabelExpr, StorageClass SC,
TypeSourceInfo *TInfo, VarDecl *);

public:
/// Perform semantic checking on a newly-created variable
/// declaration.
///
Expand Down
136 changes: 77 additions & 59 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7640,6 +7640,58 @@ static bool isMainVar(DeclarationName Name, VarDecl *VD) {
VD->isExternC());
}

void Sema::CheckAsmLabel(Scope *S, Expr *E, StorageClass SC,
TypeSourceInfo *TInfo, VarDecl *NewVD) {

// Quickly return if the function does not have an `asm` attribute.
if (E == nullptr)
return;

// The parser guarantees this is a string.
StringLiteral *SE = cast<StringLiteral>(E);
StringRef Label = SE->getString();
QualType R = TInfo->getType();
if (S->getFnParent() != nullptr) {
switch (SC) {
case SC_None:
case SC_Auto:
Diag(E->getExprLoc(), diag::warn_asm_label_on_auto_decl) << Label;
break;
case SC_Register:
// Local Named register
if (!Context.getTargetInfo().isValidGCCRegisterName(Label) &&
DeclAttrsMatchCUDAMode(getLangOpts(), getCurFunctionDecl()))
Diag(E->getExprLoc(), diag::err_asm_unknown_register_name) << Label;
break;
case SC_Static:
case SC_Extern:
case SC_PrivateExtern:
break;
}
} else if (SC == SC_Register) {
// Global Named register
if (DeclAttrsMatchCUDAMode(getLangOpts(), NewVD)) {
const auto &TI = Context.getTargetInfo();
bool HasSizeMismatch;

if (!TI.isValidGCCRegisterName(Label))
Diag(E->getExprLoc(), diag::err_asm_unknown_register_name) << Label;
else if (!TI.validateGlobalRegisterVariable(Label, Context.getTypeSize(R),
HasSizeMismatch))
Diag(E->getExprLoc(), diag::err_asm_invalid_global_var_reg) << Label;
else if (HasSizeMismatch)
Diag(E->getExprLoc(), diag::err_asm_register_size_mismatch) << Label;
}

if (!R->isIntegralType(Context) && !R->isPointerType()) {
Diag(TInfo->getTypeLoc().getBeginLoc(),
diag::err_asm_unsupported_register_type)
<< TInfo->getTypeLoc().getSourceRange();
NewVD->setInvalidDecl(true);
}
}
}

NamedDecl *Sema::ActOnVariableDeclarator(
Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo,
LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists,
Expand Down Expand Up @@ -8124,6 +8176,26 @@ NamedDecl *Sema::ActOnVariableDeclarator(
}
}

if (Expr *E = D.getAsmLabel()) {
// The parser guarantees this is a string.
StringLiteral *SE = cast<StringLiteral>(E);
StringRef Label = SE->getString();

// Insert the asm attribute.
NewVD->addAttr(AsmLabelAttr::Create(Context, Label, SE->getStrTokenLoc(0)));
} else if (!ExtnameUndeclaredIdentifiers.empty()) {
llvm::DenseMap<IdentifierInfo *, AsmLabelAttr *>::iterator I =
ExtnameUndeclaredIdentifiers.find(NewVD->getIdentifier());
if (I != ExtnameUndeclaredIdentifiers.end()) {
if (isDeclExternC(NewVD)) {
NewVD->addAttr(I->second);
ExtnameUndeclaredIdentifiers.erase(I);
} else
Diag(NewVD->getLocation(), diag::warn_redefine_extname_not_applied)
<< /*Variable*/ 1 << NewVD;
}
}

// Handle attributes prior to checking for duplicates in MergeVarDecl
ProcessDeclAttributes(S, NewVD, D);

Expand Down Expand Up @@ -8174,65 +8246,11 @@ NamedDecl *Sema::ActOnVariableDeclarator(
if (getLangOpts().ObjCAutoRefCount && ObjC().inferObjCARCLifetime(NewVD))
NewVD->setInvalidDecl();

// Handle GNU asm-label extension (encoded as an attribute).
if (Expr *E = D.getAsmLabel()) {
// The parser guarantees this is a string.
StringLiteral *SE = cast<StringLiteral>(E);
StringRef Label = SE->getString();
if (S->getFnParent() != nullptr) {
switch (SC) {
case SC_None:
case SC_Auto:
Diag(E->getExprLoc(), diag::warn_asm_label_on_auto_decl) << Label;
break;
case SC_Register:
// Local Named register
if (!Context.getTargetInfo().isValidGCCRegisterName(Label) &&
DeclAttrsMatchCUDAMode(getLangOpts(), getCurFunctionDecl()))
Diag(E->getExprLoc(), diag::err_asm_unknown_register_name) << Label;
break;
case SC_Static:
case SC_Extern:
case SC_PrivateExtern:
break;
}
} else if (SC == SC_Register) {
// Global Named register
if (DeclAttrsMatchCUDAMode(getLangOpts(), NewVD)) {
const auto &TI = Context.getTargetInfo();
bool HasSizeMismatch;

if (!TI.isValidGCCRegisterName(Label))
Diag(E->getExprLoc(), diag::err_asm_unknown_register_name) << Label;
else if (!TI.validateGlobalRegisterVariable(Label,
Context.getTypeSize(R),
HasSizeMismatch))
Diag(E->getExprLoc(), diag::err_asm_invalid_global_var_reg) << Label;
else if (HasSizeMismatch)
Diag(E->getExprLoc(), diag::err_asm_register_size_mismatch) << Label;
}

if (!R->isIntegralType(Context) && !R->isPointerType()) {
Diag(TInfo->getTypeLoc().getBeginLoc(),
diag::err_asm_unsupported_register_type)
<< TInfo->getTypeLoc().getSourceRange();
NewVD->setInvalidDecl(true);
}
}

NewVD->addAttr(AsmLabelAttr::Create(Context, Label, SE->getStrTokenLoc(0)));
} else if (!ExtnameUndeclaredIdentifiers.empty()) {
llvm::DenseMap<IdentifierInfo*,AsmLabelAttr*>::iterator I =
ExtnameUndeclaredIdentifiers.find(NewVD->getIdentifier());
if (I != ExtnameUndeclaredIdentifiers.end()) {
if (isDeclExternC(NewVD)) {
NewVD->addAttr(I->second);
ExtnameUndeclaredIdentifiers.erase(I);
} else
Diag(NewVD->getLocation(), diag::warn_redefine_extname_not_applied)
<< /*Variable*/1 << NewVD;
}
}
// Check the ASM label here, as we need to know all other attributes of the
// Decl first. Otherwise, we can't know if the asm label refers to the
// host or device in a CUDA context. The device has other registers than
// host and we must know where the function will be placed.
CheckAsmLabel(S, D.getAsmLabel(), SC, TInfo, NewVD);

// Find the shadowed declaration before filtering for scope.
NamedDecl *ShadowedDecl = D.getCXXScopeSpec().isEmpty()
Expand Down
3 changes: 3 additions & 0 deletions clang/test/Sema/attr-print.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,6 @@ int * __sptr * __ptr32 ppsp32;

// CHECK: __attribute__((availability(macos, strict, introduced=10.6)));
void f6(int) __attribute__((availability(macosx,strict,introduced=10.6)));

// CHECK: _libc_intl_domainname asm("__gi__libc_intl_domainname") __attribute__((visibility("hidden")));
extern const char _libc_intl_domainname[]; extern typeof (_libc_intl_domainname) _libc_intl_domainname asm("__gi__libc_intl_domainname") __attribute__((visibility("hidden")));