How to get values from AttributeList

I would like to parser the values of a C++ attribute in clang, but I don’t know how to get the information from the AttributeList class.

For example, is it better to use?

IdentifierLoc *Value1 = A.getArgAsIdent(0);
IdentifierLoc *Value2 = A.getArgAsIdent(1);

or

Expr *Value1 = A.getArgAsExpr(0);

Expr *Value2 = A.getArgAsExpr(1);

And later?

Thanks!

Best regards,
Luis.

I would like to parser the values of a C++ attribute in clang, but I don't
know how to get the information from the AttributeList class.

For example, is it better to use?

   IdentifierLoc *Value1 = A.getArgAsIdent(0);
   IdentifierLoc *Value2 = A.getArgAsIdent(1);

   or

  Expr *Value1 = A.getArgAsExpr(0);
  Expr *Value2 = A.getArgAsExpr(1);

And later?

A good place to look is SemaDeclAttr.cpp; that's where parsed
attributes are converted into semantic attributes that attach to
declarations. (SemaStmtAttr.cpp is where you'd go for statement
attributes; type attributes are a bit more involved and live in
SemaType.cpp).

As for whether you would be using getArgAsIdent or getArgAsExpr, that
depends entirely on the declaration of your attribute in Attr.td
(specifically, what kind of arguments it takes). Attributes that take
an IdentifierArgument, EnumArgument, or VariadicEnumArgument all use
getArgAsIdent().

HTH!

~Aaron

Hi Aaron,

I included two integers in attr.td file for this attribute declaration. I included the numbers by hand in the object creation
(I wrote a handler in SemaDeclAttr.cpp file)
and works, but I obtain error when I try to get the values form the attribute list.

Do you have any hint?

Thanks!
Luis.

Hi Aaron,

I included two integers in attr.td file for this attribute declaration. I
included the numbers by hand in the object creation
(I wrote a handler in SemaDeclAttr.cpp file)
and works, but I obtain error when I try to get the values form the
attribute list.

Do you have any hint?

Without seeing your code, it's hard to give a concrete answer, but I
suspect what you want is something like:

Expr *Arg = A.getArgAsExpr(0);
if (auto *L = dyn_cast<IntegerLiteral>(Arg)) {
  llvm::APInt V = L->getValue();
  // Do interesting things
}

~Aaron

Thanks Aaron,

It was the solution. In order to complete the information I include my complete example, If anyone needs it.

In the original source code I included an attribute named (own::custom) that receive one or more unsigned int.

[[own::custom(1,2,3,4)]]
statement;

In file tools/clang/lib/Sema/SemaStmtAttr.cpp, I included:

static Attr *handleOWNCustomAttr(Sema &S, Stmt *St, const AttributeList &A,
SourceRange Range) {
std::vector Values;
for (unsigned int i=0;i<A.getNumArgs ();++i){
Expr *Arg1 = A.getArgAsExpr(i);
if (auto *L = dyn_cast(Arg1)) {
llvm::APInt V = L->getValue();
unsigned int rint = std::atoi(V.toString(10,false).c_str());
Values.push_back(rint);
}
}
return ::new (S.Context) OWNCustomAttr(A.getRange(), S.Context, &Values[0], Values.size(),
A.getAttributeSpellingListIndex());
}

I hope that it could help anyone.

Now I have another question: I would like to get the same information with variadic enums as parameters.

I included something like (in tools/clang/include/clang/Basic/Attr.td):

def OWNCustom : Attr {
let Spellings = [CXX11<“own”, “custom”>];
let Args = [VariadicEnumArgument<“Callable”, “Consumed”,
[“AA”, “BB”, “CC”],
[“AA”, “BB”, “CC”]>];
let Documentation = [Undocumented];
}

and in file tools/clang/lib/Sema/SemaStmtAttr.cpp I included:

static Attr *handleOWNCustomAttr(Sema &S, Stmt *St, const AttributeList &A,
SourceRange Range) {

std::vectorOWNCustom::Consumed Values;

for (unsigned int i=0;i<A.getNumArgs ();++i){
IdentifierLoc *Arg1 = A.getArgAsIdent(i);
OWNCustom::Consumed Out;
if (OWNCustom::ConvertStrToConsumed (Arg1->Ident->getName(), Out)){
Values.push_back(Out);
}
}

return ::new (S.Context) OWNCustomAttr(A.getRange(), S.Context,
&Values[0], Values.size(),

A.getAttributeSpellingListIndex());
}

Evething works with only one attribute (e.g. [[own::custom(AA)]]), but fails with two or more enums (e.g. [[own::custom(AA,BB)]]).

Any help?

Thanks!

Regards,
Luis.

FYI, APInt has getters that sidestep the need to roundtrip through a string. Look for getZExtValue() and getSExtValue().

Cheers,

Jon

Thanks Aaron,

It was the solution. In order to complete the information I include my
complete example, If anyone needs it.

In the original source code I included an attribute named (own::custom) that
receive one or more unsigned int.

[[own::custom(1,2,3,4)]]
statement;

In file tools/clang/lib/Sema/SemaStmtAttr.cpp, I included:

static Attr *handleOWNCustomAttr(Sema &S, Stmt *St, const AttributeList &A,
                                   SourceRange Range) {
  std::vector<unsigned int> Values;
  for (unsigned int i=0;i<A.getNumArgs ();++i){
         Expr *Arg1 = A.getArgAsExpr(i);
          if (auto *L = dyn_cast<IntegerLiteral>(Arg1)) {
                llvm::APInt V = L->getValue();
                unsigned int rint = std::atoi(V.toString(10,false).c_str());

There's no need to use a string to convert the APInt object, btw. :wink:

                Values.push_back(rint);
          }
  }
  return ::new (S.Context) OWNCustomAttr(A.getRange(), S.Context,
&Values[0], Values.size(),

A.getAttributeSpellingListIndex());
}

I hope that it could help anyone.

Now I have another question: I would like to get the same information with
variadic enums as parameters.

I included something like (in tools/clang/include/clang/Basic/Attr.td):

def OWNCustom : Attr {
  let Spellings = [CXX11<"own", "custom">];
  let Args = [VariadicEnumArgument<"Callable", "Consumed",
                                   ["AA", "BB", "CC"],
                                   ["AA", "BB", "CC"]>];

You don't want the values and the enumerators to be the same
identifiers; that seems like a dangerous idea.

  let Documentation = [Undocumented];
}

and in file tools/clang/lib/Sema/SemaStmtAttr.cpp I included:

static Attr *handleOWNCustomAttr(Sema &S, Stmt *St, const AttributeList &A,
                                   SourceRange Range) {

  std::vector<OWNCustom::Consumed> Values;
  for (unsigned int i=0;i<A.getNumArgs ();++i){
         IdentifierLoc *Arg1 = A.getArgAsIdent(i);
         OWNCustom::Consumed Out;
         if (OWNCustom::ConvertStrToConsumed (Arg1->Ident->getName(), Out)){
                Values.push_back(Out);
          }
  }

  return ::new (S.Context) OWNCustomAttr(A.getRange(), S.Context,
                                           &Values[0], Values.size(),

A.getAttributeSpellingListIndex());
}

Evething works with only one attribute (e.g. [[own::custom(AA)]]), but fails
with two or more enums (e.g. [[own::custom(AA,BB)]]).

Any help?

Fails in what way?

Also, that code has UB when no enumeration values are provided to your
attribute (&Values[0] would be more safely written as Values.data()).

~Aaron

Thanks for your advise.

Regards,
Luis

Thanks for your comments!

I changed the enumerators like this:

def OWNCustom : Attr {
let Spellings = [CXX11<“own”, “custom”>];
let Args = [VariadicEnumArgument<“Callable”, “Consumed”,
[“aa”, “bb”, “cc”],
[“AA”, “BB”, “CC”]>];
}

however, I still have problems:

clang++ test01.cpp -std=c++1y -Xclang -ast-dump -fsyntax-only
test01.cpp:8:90: error: use of undeclared identifier ‘aa’
[[own::custom(bb,aa)]]

If I include only one parameter [[own::custom(aa)]], It works.

Any idea about what is happening?

Regards,
Luis.

Thanks for your comments!

I changed the enumerators like this:

def OWNCustom : Attr {
   let Spellings = [CXX11<"own", "custom">];
   let Args = [VariadicEnumArgument<"Callable", "Consumed",
                                    ["aa", "bb", "cc"],
                                    ["AA", "BB", "CC"]>];
}

however, I still have problems:

clang++ test01.cpp -std=c++1y -Xclang -ast-dump -fsyntax-only
test01.cpp:8:90: error: use of undeclared identifier 'aa'
    [[own::custom(bb,aa)]]

If I include only one parameter [[own::custom(aa)]], It works.

Any idea about what is happening?

It seems that variadic enumerations expect the second (and later)
arguments to be quoted strings, not identifiers. If you look at
ParseAttributeArgsCommon, only the first argument can be an
identifier. I think that's a bug, but in the meantime, you can do:

[[own::custom("bb", "aa")]] instead, and that should work.

~Aaron

Hi Aaron,

[[own::custom(“bb”, “aa”)]] doesn’t work. However, If I add the values by hand, It works:

Values.push_back(OWNCustom::AA);
Values.push_back(OWNCustom::BB);
return ::new (S.Context) OWNCustomAttr(A.getRange(), S.Context, Values.data(), Values.size(),
A.getAttributeSpellingListIndex());

Regards,
Luis.