diff --git a/clang/examples/Attribute/Attribute.cpp b/clang/examples/Attribute/Attribute.cpp --- a/clang/examples/Attribute/Attribute.cpp +++ b/clang/examples/Attribute/Attribute.cpp @@ -23,9 +23,8 @@ struct ExampleAttrInfo : public ParsedAttrInfo { ExampleAttrInfo() { - // Can take an optional string argument (the check that the argument - // actually is a string happens in handleDeclAttribute). - OptArgs = 1; + // Can take variadic arguments. + OptArgs = 15; // GNU-style __attribute__(("example")) and C++-style [[example]] and // [[plugin::example]] supported. static constexpr Spelling S[] = {{ParsedAttr::AS_GNU, "example"}, @@ -39,7 +38,7 @@ // This attribute appertains to functions only. if (!isa(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type_str) - << Attr << "functions"; + << Attr << "functions"; return false; } return true; @@ -55,23 +54,31 @@ S.Diag(Attr.getLoc(), ID); return AttributeNotApplied; } - // Check if we have an optional string argument. - StringRef Str = ""; + // Make sure there are at most three arguments exists + if (Attr.getNumArgs() > 3) { + unsigned ID = S.getDiagnostics().getCustomDiagID( + DiagnosticsEngine::Error, + "'example' attribute only allowed at most three arguments"); + S.Diag(Attr.getLoc(), ID); + return AttributeNotApplied; + } + // If has arguments, the first argument should be a string literal + Expr *Arg0 = nullptr; if (Attr.getNumArgs() > 0) { - Expr *ArgExpr = Attr.getArgAsExpr(0); + Arg0 = Attr.getArgAsExpr(0); StringLiteral *Literal = - dyn_cast(ArgExpr->IgnoreParenCasts()); - if (Literal) { - Str = Literal->getString(); - } else { - S.Diag(ArgExpr->getExprLoc(), diag::err_attribute_argument_type) - << Attr.getAttrName() << AANT_ArgumentString; + dyn_cast(Arg0->IgnoreParenCasts()); + if (!Literal) { + unsigned ID = S.getDiagnostics().getCustomDiagID( + DiagnosticsEngine::Error, + "'example's first argument should be a string literal"); + S.Diag(Attr.getLoc(), ID); return AttributeNotApplied; } } // Attach an annotate attribute to the Decl. - D->addAttr(AnnotateAttr::Create(S.Context, "example(" + Str.str() + ")", - Attr.getRange())); + D->addAttr(AnnotateAttr::Create(S.Context, "example", &Arg0, + Attr.getNumArgs(), Attr.getRange())); return AttributeApplied; } }; diff --git a/clang/test/Frontend/plugin-attribute.cpp b/clang/test/Frontend/plugin-attribute.cpp --- a/clang/test/Frontend/plugin-attribute.cpp +++ b/clang/test/Frontend/plugin-attribute.cpp @@ -1,25 +1,23 @@ -// RUN: %clang -fplugin=%llvmshlibdir/Attribute%pluginext -emit-llvm -S %s -o - 2>&1 | FileCheck %s --check-prefix=ATTRIBUTE -// RUN: not %clang -fplugin=%llvmshlibdir/Attribute%pluginext -emit-llvm -DBAD_ATTRIBUTE -S %s -o - 2>&1 | FileCheck %s --check-prefix=BADATTRIBUTE +// RUN: %clang -fplugin=%llvmshlibdir/Attribute%pluginext -DGOOD_ATTR -fsyntax-only -Xclang -verify=goodattr %s +// RUN: %clang -fplugin=%llvmshlibdir/Attribute%pluginext -DBAD_ATTR -fsyntax-only -Xclang -verify=badattr %s // REQUIRES: plugins, examples - +#ifdef GOOD_ATTR +// goodattr-no-diagnostics void fn1a() __attribute__((example)) { } [[example]] void fn1b() { } [[plugin::example]] void fn1c() { } void fn2() __attribute__((example("somestring"))) { } -// ATTRIBUTE: warning: 'example' attribute only applies to functions -int var1 __attribute__((example("otherstring"))) = 1; - -// ATTRIBUTE: [[STR1_VAR:@.+]] = private unnamed_addr constant [10 x i8] c"example()\00" -// ATTRIBUTE: [[STR2_VAR:@.+]] = private unnamed_addr constant [20 x i8] c"example(somestring)\00" -// ATTRIBUTE: @llvm.global.annotations = {{.*}}@{{.*}}fn1a{{.*}}[[STR1_VAR]]{{.*}}@{{.*}}fn1b{{.*}}[[STR1_VAR]]{{.*}}@{{.*}}fn1c{{.*}}[[STR1_VAR]]{{.*}}@{{.*}}fn2{{.*}}[[STR2_VAR]] +#endif -#ifdef BAD_ATTRIBUTE +#ifdef BAD_ATTR +// badattr-warning@14 {{'example' attribute only applies to functions}} +int var1 __attribute__((example("otherstring"))) = 1; class Example { - // BADATTRIBUTE: error: 'example' attribute only allowed at file scope + // badattr-error@17 {{'example' attribute only allowed at file scope}} void __attribute__((example)) fn3(); }; -// BADATTRIBUTE: error: 'example' attribute requires a string +// badattr-error@20 {{'example's first argument should be a string literal}} void fn4() __attribute__((example(123))) { } -// BADATTRIBUTE: error: 'example' attribute takes no more than 1 argument -void fn5() __attribute__((example("a","b"))) { } +// badattr-error@22 {{'example' attribute only allowed at most three arguments}} +void fn5() __attribute__((example("a","b", 3, 4.0))) { } #endif