[patch][pr17535] Reject alias attributes that point to undefined names.

Aaron Ballman aaron at aaronballman.com
Sun Oct 20 07:56:42 PDT 2013


Some minor comments below:

> diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
> index 381eaeb..37d8a4d 100644
> --- a/include/clang/Basic/Attr.td
> +++ b/include/clang/Basic/Attr.td
> @@ -176,6 +176,7 @@ def AddressSpace : TypeAttr {
>  def Alias : InheritableAttr {
>    let Spellings = [GNU<"alias">, CXX11<"gnu", "alias">];
>    let Args = [StringArgument<"Aliasee">];
> +  let AdditionalMembers = [{ NamedDecl *AliaseeDecl; }];
>  }
>
>  def Aligned : InheritableAttr {
> diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
> index d8fef68..3250e4f 100644
> --- a/include/clang/Basic/DiagnosticSemaKinds.td
> +++ b/include/clang/Basic/DiagnosticSemaKinds.td
> @@ -2015,6 +2015,8 @@ def err_attribute_weakref_without_alias : Error<
>    "weakref declaration of '%0' must also have an alias attribute">;
>  def err_alias_not_supported_on_darwin : Error <
>    "only weak aliases are supported on darwin">;
> +def err_alias_to_undefined : Error<
> +  "alias must point to a defined variable or function">;

I would prefer to see what the aliasee's name is as part of the
diagnostic.  Also, I think we're trending towards having the
attribute's name come from the attribute itself, and be quoted.

>  def warn_attribute_wrong_decl_type : Warning<
>    "%0 attribute only applies to %select{functions|unions|"
>    "variables and functions|functions and methods|parameters|"
> diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
> index 65f07a8..c161f53 100644
> --- a/include/clang/Sema/Sema.h
> +++ b/include/clang/Sema/Sema.h
> @@ -372,6 +372,8 @@ public:
>    /// cycle detection at the end of the TU.
>    DelegatingCtorDeclsType DelegatingCtorDecls;
>
> +  SmallVector<Decl*, 2> Aliases;
> +
>    /// \brief All the overriding destructors seen during a class definition
>    /// (there could be multiple due to nested classes) that had their exception
>    /// spec checks delayed, plus the overridden destructor.
> @@ -954,6 +956,8 @@ public:
>
>    void ActOnEndOfTranslationUnit();
>
> +  void CheckAliases();
> +
>    void CheckDelegatingCtorCycles();
>
>    Scope *getScopeForContext(DeclContext *Ctx);
> diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
> index 2844fe2..6d146d6 100644
> --- a/lib/CodeGen/CGExprCXX.cpp
> +++ b/lib/CodeGen/CGExprCXX.cpp
> @@ -928,9 +928,8 @@ static RValue EmitNewDeleteCall(CodeGenFunction &CGF,
>    ///   to a replaceable global allocation function.
>    ///
>    /// We model such elidable calls with the 'builtin' attribute.
> -  llvm::Function *Fn = dyn_cast<llvm::Function>(CalleeAddr);
>    if (Callee->isReplaceableGlobalAllocationFunction() &&
> -      Fn && Fn->hasFnAttribute(llvm::Attribute::NoBuiltin)) {
> +      !Callee->hasAttr<AliasAttr>()) {
>      // FIXME: Add addAttribute to CallSite.
>      if (llvm::CallInst *CI = dyn_cast<llvm::CallInst>(CallOrInvoke))
>        CI->addAttribute(llvm::AttributeSet::FunctionIndex,
> diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
> index 96ae437..1ce6285 100644
> --- a/lib/CodeGen/CodeGenModule.cpp
> +++ b/lib/CodeGen/CodeGenModule.cpp
> @@ -933,6 +933,12 @@ void CodeGenModule::EmitDeferred() {
>      GlobalDecl D = DeferredDeclsToEmit.back();
>      DeferredDeclsToEmit.pop_back();
>
> +    const ValueDecl *Global = cast<ValueDecl>(D.getDecl());
> +    if (Global->hasAttr<AliasAttr>()) {
> +      EmitAliasDefinition(D);
> +      continue;
> +    }
> +
>      // Check to see if we've already emitted this.  This is necessary
>      // for a couple of reasons: first, decls can end up in the
>      // deferred-decls queue multiple times, and second, decls can end
> @@ -1098,7 +1104,7 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
>    // If this is an alias definition (which otherwise looks like a declaration)
>    // emit it now.
>    if (Global->hasAttr<AliasAttr>())
> -    return EmitAliasDefinition(GD);
> +    DeferredDeclsToEmit.push_back(GD);
>
>    // If this is CUDA, be selective about which declarations we emit.
>    if (LangOpts.CUDA) {
> @@ -2093,12 +2099,14 @@ void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) {
>    // Create a reference to the named value.  This ensures that it is emitted
>    // if a deferred decl.
>    llvm::Constant *Aliasee;
> -  if (isa<llvm::FunctionType>(DeclTy))
> -    Aliasee = GetOrCreateLLVMFunction(AA->getAliasee(), DeclTy, GD,
> -                                      /*ForVTable=*/false);
> -  else
> -    Aliasee = GetOrCreateLLVMGlobal(AA->getAliasee(),
> -                                    llvm::PointerType::getUnqual(DeclTy), 0);
> +  if (FunctionDecl *F = dyn_cast<FunctionDecl>(AA->AliaseeDecl)) {
> +    GlobalDecl GDA(F);
> +    Aliasee = GetAddrOfFunction(GDA, DeclTy, /*ForVTable=*/false);
> +  }
> +  else {
> +    VarDecl *Var = cast<VarDecl>(AA->AliaseeDecl);
> +    Aliasee = GetAddrOfGlobalVar(Var,DeclTy);
> +  }
>
>    // Create the new alias itself, but don't set a name yet.
>    llvm::GlobalValue *GA =
> diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
> index 41f72a6..96f0a3e 100644
> --- a/lib/Sema/Sema.cpp
> +++ b/lib/Sema/Sema.cpp
> @@ -557,6 +557,36 @@ static bool IsRecordFullyDefined(const CXXRecordDecl *RD,
>    return Complete;
>  }
>
> +static bool isValidAliasee(NamedDecl *ND) {
> +  if (!ND)
> +    return false;
> +  FunctionDecl *FD = dyn_cast<FunctionDecl>(ND);
> +  if (FD)
> +    return FD->isDefined();
> +  VarDecl *VD = dyn_cast<VarDecl>(ND);
> +  if (!VD)
> +    return false;
> +  return VD->hasDefinition() != VarDecl::DeclarationOnly;
> +}
> +
> +void Sema::CheckAliases() {
> +  for (SmallVectorImpl<Decl*>::iterator I = Aliases.begin(), E = Aliases.end();
> +       I != E; ++I) {
> +    Decl *D = *I;
> +    if (D->hasAttr<WeakRefAttr>())
> +      continue;
> +    AliasAttr *AA = D->getAttr<AliasAttr>();

Can a Decl have multiple AliasAttrs?  If so, this becomes problematic.
 If it's not allowed, we should have a diagnostic and test for it.

> +    StringRef Name = AA->getAliasee();
> +    const IdentifierInfo *NameI = &Context.Idents.get(Name);
> +    SourceLocation NameLoc = AA->getLocation();
> +    NamedDecl *Aliasee =
> +        LookupSingleName(TUScope, NameI, NameLoc, LookupOrdinaryName);
> +    if (!isValidAliasee(Aliasee))
> +      Diag(NameLoc, diag::err_alias_to_undefined);
> +    AA->AliaseeDecl = Aliasee;
> +  }
> +}
> +
>  /// ActOnEndOfTranslationUnit - This is called at the very end of the
>  /// translation unit when EOF is reached and all but the top-level scope is
>  /// popped.
> @@ -638,6 +668,8 @@ void Sema::ActOnEndOfTranslationUnit() {
>        << I->first;
>    }
>
> +  CheckAliases();
> +
>    if (LangOpts.CPlusPlus11 &&
>        Diags.getDiagnosticLevel(diag::warn_delegating_ctor_cycle,
>                                 SourceLocation())
> diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
> index d7c4f78..317bde4 100644
> --- a/lib/Sema/SemaDecl.cpp
> +++ b/lib/Sema/SemaDecl.cpp
> @@ -1977,7 +1977,10 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D, InheritableAttr *Attr,
>    else if (SectionAttr *SA = dyn_cast<SectionAttr>(Attr))
>      NewAttr = S.mergeSectionAttr(D, SA->getRange(), SA->getName(),
>                                   AttrSpellingListIndex);
> -  else if (isa<AlignedAttr>(Attr))
> +  else if (isa<AliasAttr>(Attr)) {
> +    NewAttr = cast<InheritableAttr>(Attr->clone(S.Context));
> +    S.Aliases.push_back(D);
> +  } else if (isa<AlignedAttr>(Attr))
>      // AlignedAttrs are handled separately, because we need to handle all
>      // such attributes on a declaration at the same time.
>      NewAttr = 0;
> diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
> index 3eabf87..a0bcace 100644
> --- a/lib/Sema/SemaDeclAttr.cpp
> +++ b/lib/Sema/SemaDeclAttr.cpp
> @@ -1681,10 +1681,10 @@ static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) {
>      return;
>    }
>
> -  // FIXME: check if target symbol exists in current file
>
>    D->addAttr(::new (S.Context) AliasAttr(Attr.getRange(), S.Context, Str,
>                                           Attr.getAttributeSpellingListIndex()));
> +  S.Aliases.push_back(D);
>  }
>
>  static void handleMinSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
> @@ -5015,10 +5015,17 @@ void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) {
>    W.setUsed(true);
>    if (W.getAlias()) { // clone decl, impersonate __attribute(weak,alias(...))
>      IdentifierInfo *NDId = ND->getIdentifier();
> +
> +    NamedDecl *Aliasee = LookupSingleName(TUScope, W.getAlias(),
> +                                          W.getLocation(), LookupOrdinaryName);
> +    if (Aliasee && Aliasee->hasAttr<AliasAttr>())
> +      return;
> +
>      NamedDecl *NewD = DeclClonePragmaWeak(ND, W.getAlias(), W.getLocation());
>      NewD->addAttr(::new (Context) AliasAttr(W.getLocation(), Context,
>                                              NDId->getName()));
>      NewD->addAttr(::new (Context) WeakAttr(W.getLocation(), Context));
> +    Aliases.push_back(NewD);
>      WeakTopLevelDecl.push_back(NewD);
>      // FIXME: "hideous" code from Sema::LazilyCreateBuiltin
>      // to insert Decl at TU scope, sorry.
> diff --git a/test/CodeGen/alias.c b/test/CodeGen/alias.c
> index efa94b3..31ba9a9 100644
> --- a/test/CodeGen/alias.c
> +++ b/test/CodeGen/alias.c
> @@ -6,6 +6,10 @@ int g0;
>  static int bar1 = 42;
>  // CHECKBASIC: @bar1 = internal global i32 42
>
> +static int bar2() {
> +  return 0;
> +}
> +
>  extern int g1;
>  extern int g1 __attribute((alias("g0")));
>  // CHECKBASIC-DAG: @g1 = alias i32* @g0
> @@ -34,11 +38,11 @@ static int inner_weak(int a) { return 0; }
>  extern __typeof(inner) inner_a __attribute__((alias("inner")));
>  static __typeof(inner_weak) inner_weak_a __attribute__((weakref, alias("inner_weak")));
>  // CHECKCC: @inner_a = alias i32 (i32)* @inner
> -// CHECKCC: define internal arm_aapcs_vfpcc i32 @inner(i32 %a) [[NUW:#[0-9]+]] {

Why is this being moved lower and losing the [0-9]+ check?

>
>  int outer(int a) { return inner(a); }
> -// CHECKCC: define arm_aapcs_vfpcc i32 @outer(i32 %a) [[NUW]] {
> +// CHECKCC: define arm_aapcs_vfpcc i32 @outer(i32 %a) [[NUW:#[0-9]+]] {
>  // CHECKCC: call arm_aapcs_vfpcc  i32 @inner(i32 %{{.*}})
> +// CHECKCC: define internal arm_aapcs_vfpcc i32 @inner(i32 %a) [[NUW]] {
>
>  int outer_weak(int a) { return inner_weak_a(a); }
>  // CHECKCC: define arm_aapcs_vfpcc i32 @outer_weak(i32 %a) [[NUW]] {
> diff --git a/test/CodeGenCXX/attr.cpp b/test/CodeGenCXX/attr.cpp
> index 8bcff36..4a78054 100644
> --- a/test/CodeGenCXX/attr.cpp
> +++ b/test/CodeGenCXX/attr.cpp
> @@ -29,6 +29,6 @@ void C::bar4() { }
>  // CHECK-LABEL: define i32 @_Z5test1v()
>  int test1() { return 10; }
>  // CHECK at top of file
> -extern "C" int test2() __attribute__((alias("_Z5test1v")));
> +extern "C" int test2() __attribute__((alias("test1")));

So are we removing the functionality allowing to look up mangled names?

>
>  // CHECK: attributes [[NUW]] = { nounwind{{.*}} }
> diff --git a/test/Misc/ast-dump-attr.cpp b/test/Misc/ast-dump-attr.cpp
> index 3efcd09..2ea1f9e 100644
> --- a/test/Misc/ast-dump-attr.cpp
> +++ b/test/Misc/ast-dump-attr.cpp
> @@ -79,6 +79,7 @@ void TestInt(void) __attribute__((constructor(123)));
>  // CHECK:      FunctionDecl{{.*}}TestInt
>  // CHECK-NEXT:   ConstructorAttr{{.*}} 123
>
> +int alias1;
>  int TestString __attribute__((alias("alias1")));
>  // CHECK:      VarDecl{{.*}}TestString
>  // CHECK-NEXT:   AliasAttr{{.*}} "alias1"
> diff --git a/test/Sema/attr-alias-elf.c b/test/Sema/attr-alias-elf.c
> new file mode 100644
> index 0000000..55cae9b
> --- /dev/null
> +++ b/test/Sema/attr-alias-elf.c
> @@ -0,0 +1,22 @@
> +// RUN: %clang_cc1 -triple x86_64-pc-linux  -fsyntax-only -verify %s
> +
> +void f1(void) __attribute__((alias("g1")));
> +void g1(void) {
> +}
> +
> +void f2(void) __attribute__((alias("g2"))); // expected-error {{alias must point to a defined variable or function}}
> +
> +
> +void f3(void) __attribute__((alias("g3"))); // expected-error {{alias must point to a defined variable or function}}
> +void g3(void);
> +
> +extern int a1 __attribute__((alias("b1")));
> +int b1 = 42;
> +
> +extern int a2 __attribute__((alias("b2"))); // expected-error {{alias must point to a defined variable or function}}
> +
> +extern int a3 __attribute__((alias("b3"))); // expected-error {{alias must point to a defined variable or function}}
> +extern int b3;
> +
> +extern int a4 __attribute__((alias("b4"))); // expected-error {{alias must point to a defined variable or function}}

Ugh... I wish there was a way we could use the existing mechanisms for
dealing with this.  Namely, using a resolved identifier instead of a
string literal.  This way, the error reporting can be more
consistent...

> +typedef int b4;
> diff --git a/test/SemaCXX/cxx11-gnu-attrs.cpp b/test/SemaCXX/cxx11-gnu-attrs.cpp
> index def83a9..f587805 100644
> --- a/test/SemaCXX/cxx11-gnu-attrs.cpp
> +++ b/test/SemaCXX/cxx11-gnu-attrs.cpp
> @@ -12,7 +12,7 @@ int *[[gnu::unused]] attr_on_ptr;
>  // Valid cases.
>
>  void alias1() {}
> -void alias2 [[gnu::alias("_Z6alias1v")]] ();
> +void alias2 [[gnu::alias("alias1")]] ();

Same here as above.

>
>  [[gnu::aligned(8)]] int aligned;
>  void aligned_fn [[gnu::aligned(32)]] ();
>

~Aaron

On Sat, Oct 19, 2013 at 6:54 PM, Rafael EspĂ­ndola
<rafael.espindola at gmail.com> wrote:
> ping
>
>> On 14 October 2013 12:31, Rafael EspĂ­ndola <rafael.espindola at gmail.com> wrote:
>>> The attached patch causes clang to reject alias attributes that point
>>> to undefined names. For example, with this patch we now reject
>>>
>>> void f1(void) __attribute__((alias("g1")));
>>>
>>> if g1 is not defined in this file. This matches "modern" gcc (>= 4.2
>>> at least) behavior. What is different in this implementation is that
>>> we use the C/C++ level names, not the assembly names like gcc does.
>>> This is consistent with our implementation of #pragma weak, with has
>>> the same difference to gcc's implementation.
>>>
>>> Other options include
>>> * Using the mangled name from sema. This would be very expensive and
>>> we would have to mangle each decl to see if we got it.
>>> * Produce a terse error from CodeGen. We normally avoid this, but it
>>> is probably the right thing to do here if we decide to use the mangled
>>> names.
>
> Cheers,
> Rafael
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>




More information about the cfe-commits mailing list